diff options
25 files changed, 3074 insertions, 2777 deletions
diff --git a/firmware/x300/lib/ethernet.c b/firmware/x300/lib/ethernet.c index fdde9e41b..7a86980c7 100644 --- a/firmware/x300/lib/ethernet.c +++ b/firmware/x300/lib/ethernet.c @@ -82,7 +82,7 @@ ethernet_ninterfaces(void) // Clause 45 MDIO used for 10Gig Ethernet has two bus transactions to complete a transfer. // An initial transaction sets up the address, and a subsequent one transfers the read or write data. // -static uint32_t +static uint32_t xge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t device, const uint32_t port) { // Set register address each iteration @@ -103,9 +103,9 @@ xge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t device return(xge_regs->mdio_data); } -static void +static void xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t device, const uint32_t port, const uint32_t data) -{ +{ // Set register address each iteration xge_regs->mdio_addr = address; // Its a clause 45 device. We want to ADDRESS @@ -114,13 +114,13 @@ xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t devic xge_regs->mdio_control = 1; // Wait until bus transaction complete while (xge_regs->mdio_control == 1); - // Write new value to mdio_write_data reg. - xge_regs->mdio_data = data; - // Its a clause 45 device. We want to WRITE + // Write new value to mdio_write_data reg. + xge_regs->mdio_data = data; + // Its a clause 45 device. We want to WRITE xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE45) | XGE_MDIO_OP(MDIO_WRITE) | XGE_MDIO_ADDR(port) | XGE_MDIO_MMD(device); - // Start MDIO bus transaction - xge_regs->mdio_control = 1; - // Wait until bus transaction complete + // Start MDIO bus transaction + xge_regs->mdio_control = 1; + // Wait until bus transaction complete while (xge_regs->mdio_control == 1); } @@ -128,7 +128,7 @@ xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t devic // // Clause 22 MDIO used for 1Gig Ethernet has one bus transaction to complete a transfer. // -static uint32_t +static uint32_t ge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t port) { // Its a clause 22 device. We want to READ @@ -141,16 +141,16 @@ ge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t port) return(xge_regs->mdio_data); } -static void +static void ge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t port, const uint32_t data) { - // Write new value to mdio_write_data reg. - xge_regs->mdio_data = data; - // Its a clause 22 device. We want to WRITE + // Write new value to mdio_write_data reg. + xge_regs->mdio_data = data; + // Its a clause 22 device. We want to WRITE xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE22) | XGE_MDIO_OP(MDIO_C22_WRITE) | XGE_MDIO_ADDR(port) | address; - // Start MDIO bus transaction - xge_regs->mdio_control = 1; - // Wait until bus transaction complete + // Start MDIO bus transaction + xge_regs->mdio_control = 1; + // Wait until bus transaction complete while (xge_regs->mdio_control == 1); } @@ -205,7 +205,7 @@ xge_i2c_rd(const uint32_t base, const uint8_t i2c_dev_addr, const uint8_t i2c_wo // Now read back a byte of data if (wb_i2c_read(base, i2c_dev_addr, &buf, 1) == false) return(-1); - + return((int) buf); } @@ -334,15 +334,15 @@ xge_phy_init(const uint8_t eth, const uint32_t mdio_port) printf("INFO: Begining XGE PHY init sequence.\n"); // Software reset x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port); - x = x | (1 << 15); - write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); + x = x | (1 << 15); + write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); while(x&(1<<15)) x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port); } void xge_poll_sfpp_status(const uint32_t eth) -{ +{ uint32_t x; // Has MODDET/MODAbS changed since we last looked? x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); @@ -355,14 +355,20 @@ xge_poll_sfpp_status(const uint32_t eth) printf("DEBUG: eth%1d MODABS changed state: %d\n", eth, (x & SFPP_STATUS_MODABS) >> 2); if (x & (SFPP_STATUS_RXLOS_CHG|SFPP_STATUS_TXFAULT_CHG|SFPP_STATUS_MODABS_CHG)) - if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) { - xge_ethernet_init(eth); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - mdelay(100); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - mdelay(100); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); + { + if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) + { + if (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1) + { + xge_ethernet_init(eth); + dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); + mdelay(100); + dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); + mdelay(100); + dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); } + } + } if (x & SFPP_STATUS_MODABS_CHG) { // MODDET has changed state since last checked @@ -383,14 +389,14 @@ xge_poll_sfpp_status(const uint32_t eth) //The link became up, send a GARP so everyone knows our mac/ip association if (!old_link_up && links_up[eth]) u3_net_stack_send_arp_request(eth, u3_net_stack_get_ip_addr(eth)); } - + void xge_ethernet_init(const uint32_t eth) -{ - xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); - //xge_hard_phy_reset(); - xge_phy_init(eth ,MDIO_PORT); +{ + xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); + //xge_hard_phy_reset(); + xge_phy_init(eth ,MDIO_PORT); uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); printf(" eth%1d SFP initial state: RXLOS: %d TXFAULT: %d MODABS: %d\n", eth, @@ -411,7 +417,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) printf("%x",device); printf(" "); switch(address) { - case XGE_MDIO_CONTROL1: + case XGE_MDIO_CONTROL1: printf("CONTROL1: "); printf("%x",data); printf(" "); for (x=15; x >= 0 ; x--) @@ -423,7 +429,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 11: printf("Low Power Mode,"); break; case 5:case 4:case 3:case 2: printf("RESERVED speed value,"); break; case 0: printf("PMA loopback,"); break; - } //else + } //else // Bits clear. //switch (x) { //case 13: case 6: printf(" None 10Gb/s speed set!"); break; @@ -440,7 +446,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 7: printf("Fault Detected,"); break; case 2: printf("Link is Up,"); break; case 1: printf("Supports Low Power,"); break; - } else + } else // Bits Clear switch(x) { case 2: printf("Link is Down,"); break; @@ -457,7 +463,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 15:case 14:case 13:case 12:case 11:case 10:case 9: case 8:case 7:case 6:case 5:case 4:case 3:case 2:case 1: printf("RESERVED bits set!,"); break; case 0: printf("Capable of 10Gb/s,"); - } else + } else // Bits clear. switch(x) { case 0: printf("Incapable of 10Gb/s,"); break; @@ -572,7 +578,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 2: printf("Lane 2 not synced,"); break; case 1: printf("Lane 1 not synced,"); break; case 0: printf("Lane 0 not synced,"); break; - } + } printf(" \n"); break; case XILINX_CORE_VERSION: @@ -591,23 +597,23 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) } } -void +void dump_mdio_regs(const uint8_t eth, uint32_t mdio_port) { volatile unsigned int x; int y; unsigned int regs_a[9] = {0,1,4,5,6,7,8,32,33}; unsigned int regs_b[10] = {0,1,4,5,6,7,8,10,11,65535}; - + printf("\n"); - for (y = 0; y < 10; y++) + for (y = 0; y < 10; y++) { // Read MDIO data x = read_mdio(eth,regs_b[y],XGE_MDIO_DEVICE_PMA,mdio_port); decode_reg(regs_b[y],XGE_MDIO_DEVICE_PMA,x); } - + for (y = 0; y < 9; y++) { // Read MDIO data diff --git a/firmware/x300/x300/x300_init.c b/firmware/x300/x300/x300_init.c index 2ddfef86b..66fb120f3 100644 --- a/firmware/x300/x300/x300_init.c +++ b/firmware/x300/x300/x300_init.c @@ -75,6 +75,7 @@ static void init_network(void) pkt_config = wb_pkt_iface64_init(PKT_RAM0_BASE, 0x1ffc); printf("PKT RAM0 BASE 0x%x\n", (&pkt_config)->base); u3_net_stack_init(&pkt_config); + link_state_route_proto_init(); //read everything from eeprom diff --git a/firmware/x300/x300/x300_main.c b/firmware/x300/x300/x300_main.c index 5f7c19624..809f181ba 100644 --- a/firmware/x300/x300/x300_main.c +++ b/firmware/x300/x300/x300_main.c @@ -372,15 +372,26 @@ static void handle_uarts(void) **********************************************************************/ static void update_forwarding(const uint8_t e) { + /* FIXME: This code is broken. + * It blindly enables forwarding without regard to whether or not + * packets can be forwarded. If one of the Ethernet interfaces is not + * connected, data backs up until the first interface becomes unresponsive. + * + * And for more fun, we had to re-enable forwarding of packets that were not + * addressed to this device's MAC address to work around an issue that was + * causing sequence errors. + */ //update forwarding rules uint32_t forward = 0; if (!link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) { - forward |= (1 << 0); //forward bcast + //FIXME: Uncomment when forwarding of broadcasts is properly handled + //forward |= (1 << 0); //forward bcast forward |= (1 << 1); //forward not mac dest } const uint32_t eth_base = (e == 0)? SR_ETHINT0 : SR_ETHINT1; wb_poke32(SR_ADDR(SET0_BASE, eth_base + 8 + 4), forward); + } static void handle_link_state(void) @@ -390,13 +401,9 @@ static void handle_link_state(void) shmem[X300_FW_SHMEM_ROUTE_MAP_ADDR] = (uint32_t)link_state_route_get_node_mapping(&map_len); shmem[X300_FW_SHMEM_ROUTE_MAP_LEN] = map_len; - //update forwarding for all eths - //low overhead: this does not run the algorithm - for (uint8_t e = 0; e < ethernet_ninterfaces(); e++) update_forwarding(e); - static size_t count = 0; - if (count++ < 2000) return; //2 seconds - count = 0; + if (count--) return; + count = 2000; //repeat every ~2 seconds link_state_route_proto_tick(); for (size_t e = 0; e < ethernet_ninterfaces(); e++) @@ -406,7 +413,12 @@ static void handle_link_state(void) link_state_route_proto_update(e); link_state_route_proto_flood(e); } + + //update forwarding if something changed + bool before = link_state_route_proto_causes_cycle_cached(e, (e+1)%2); link_state_route_proto_update_cycle_cache(e); + if (before != link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) + update_forwarding(e); /* printf("is there a cycle %s -> %s? %s\n", ip_addr_to_str(u3_net_stack_get_ip_addr(e)), diff --git a/fpga/usrp3/top/x300/coregen/bootram.coe b/fpga/usrp3/top/x300/coregen/bootram.coe index 075e91f39..98796a4c6 100755 --- a/fpga/usrp3/top/x300/coregen/bootram.coe +++ b/fpga/usrp3/top/x300/coregen/bootram.coe @@ -2,15 +2,15 @@ memory_initialization_radix=16; memory_initialization_vector= 0b0b0b0b, 82700b0b, -8187b00c, +8186f40c, 3a0b0b80, -f28f0400, +eef50400, 00000000, 00000000, 00000000, 80088408, 88080b0b, -80f2da2d, +80efc02d, 880c840c, 800c0400, 00000000, @@ -161,8 +161,8 @@ c4040000, 00000000, 00000000, 71fc0608, -0b0b8187, -9c738306, +0b0b8186, +e0738306, 10100508, 060b0b0b, 88aa0400, @@ -170,16 +170,16 @@ c4040000, 00000000, 80088408, 88087575, -0b0b80e9, -b42d5050, +0b0b80e7, +dd2d5050, 80085688, 0c840c80, 0c510400, 00000000, 80088408, 88087575, -0b0b80ea, -e62d5050, +0b0b80e9, +8f2d5050, 80085688, 0c840c80, 0c510400, @@ -209,7 +209,7 @@ e62d5050, 00000000, 00000000, 810b0b0b, -8187ac0c, +8186f00c, 51040000, 00000000, 00000000, @@ -257,7 +257,7 @@ e62d5050, 00000000, 00000000, 82813f80, -ebfb3f04, +e8e13f04, 10101010, 10101010, 10101010, @@ -280,56 +280,56 @@ fc060c51, 0a100a53, 72ed3851, 51535104, -8187ac08, +8186f008, 802ea438, -8187b008, +8186f408, 822ebd38, 8380800b, -0b0b818f, -a40c82a0, -800b818f, -a80c8290, -800b818f, -ac0c04f8, +0b0b818e, +e80c82a0, +800b818e, +ec0c8290, +800b818e, +f00c04f8, 808080a4, 0b0b0b81, -8fa40cf8, +8ee80cf8, 80808280, -0b818fa8, +0b818eec, 0cf88080, 84800b81, -8fac0c04, +8ef00c04, 80c0a880, 8c0b0b0b, -818fa40c, +818ee80c, 80c0a880, -940b818f, -a80c0b0b, -80f4b00b, -818fac0c, +940b818e, +ec0c0b0b, +80f1940b, +818ef00c, 04ff3d0d, -818fb033, +818ef433, 5170a738, -8187b808, +8186fc08, 70085252, 70802e94, 38841281, -87b80c70, -2d8187b8, +86fc0c70, +2d8186fc, 08700852, 5270ee38, -810b818f, -b034833d, +810b818e, +f434833d, 0d040480, 3d0d0b0b, -818fa008, +818ee408, 802e8e38, 0b0b0b0b, 800b802e, 09810685, 38823d0d, 040b0b81, -8fa0510b, +8ee4510b, 0b0bf5d4, 3f823d0d, 0404f93d, @@ -354,455 +354,461 @@ b1387218, 73833877, 5170800c, 893d0d04, -04e23d0d, +ff3d0d02, +93053352, +83f28051, +97863f83, +3d0d04e2, +3d0d8bef, +5283fa80, +5196e93f, 8bef5283, -fa805198, -823f8bef, -5283f280, -5197f83f, -8b885280, -51a2a73f, -81af5280, -f4b851a2, -a83f80d3, +f2805196, +df3f8b88, +528051a1, +8d3f81af, +5280f19c, +51a18e3f, +80d3b993, +c05283fc, +80519785, +3f80d3b9, +93c05283, +fe805196, +f83f80d3, b993c052, -83fc8051, -989e3f80, -d3b993c0, +83f88051, +96eb3f81, +0b82c084, +0c82c090, +08558a56, +74812e83, +38815675, +5280f1c8, +51a0ca3f, +82c09408, +558a5674, +812e8338, +81567552, +80f1e051, +a0b33fbf, +fc538280, +8052818e, +f851a1ca, +3f818ef8, +085280f1, +f851a099, +3f818ef8, +51a68e3f, +8d3d5b80, +cc538187, +80527a51, +80dffe3f, +825480f1, +985380d0, 5283fe80, -5198913f, -80d3b993, -c05283f8, -80519884, -3f810b82, -c0840c82, +5197c03f, +80cc547a, +5380d052, +83fe8051, +96983f82, c0900855, -8a567481, -2e833881, -56755280, -f4e451a1, -e43f82c0, -9408558a, -5674812e, -83388156, -755280f4, -fc51a1cd, -3fbffc53, -82808052, -818fb451, -a2e43f81, -8fb40852, -80f59451, -a1b33f81, -8fb451a7, -a83f80da, -843f8d3d, -5b80cc53, -8187bc52, -7a5180e1, -e33f8254, -80f4b453, -80d05283, -fe805198, -d53f80cc, -547a5380, -d05283fe, -805197ad, -3f82c090, -08558257, -74833874, -5782c094, -0855835c, -74833881, -5c865381, -87c452a0, -3dffbc05, -51fdab3f, -80085686, -538187cc, -52a03dc4, -0551fd9a, -3f800858, -84537682, -2b8187e8, -1153701c, -ac115358, -55fd833f, -80085a84, -538187d8, -15529c17, -51fcf33f, -80085984, -537b822b, -8187e811, -53701cac, -11535855, -fcdc3f80, -085b8453, -8187d815, -529c1751, -fccc3f80, -0879557a, -54765357, -8051a681, -3f841633, -85173371, -882b0783, -18337090, -2b720782, -1a337098, -2b720782, -c1c00c7a, -33811c33, +82577483, +38745782, +c0940855, +835c7483, +38815c86, +53818788, +52a03dff, +bc0551fd, +9d3f8008, +56865381, +879052a0, +3dc40551, +fd8c3f80, +08588453, +76822b81, +87ac1153, +701cac11, +535855fc, +f53f8008, +5a845381, +879c1552, +9c1751fc, +e53f8008, +5984537b, +822b8187, +ac115370, +1cac1153, +5855fcce, +3f80085b, +84538187, +9c15529c, +1751fcbe, +3f800879, +557a5476, +53578051, +a4eb3f84, +16338517, +3371882b, +07831833, +70902b72, +07821a33, +70982b72, +0782c1c0, +0c7a3381, +1c337188, +2b0782c1, +c40c7f08, +82c1c80c, +535d5252, +565c800b, +82c1d00c, +9e800b82, +c1d40c76, +547a5377, +528151a4, +9c3f8418, +33851933, 71882b07, -82c1c40c, -7f0882c1, -c80c535d, -5252565c, -800b82c1, -d00c9e80, -0b82c1d4, -0c76547a, -53775281, -51a5b23f, -84183385, -19337188, -2b07831a, -3370902b, -7207821c, -3370982b, -720782c2, -800c7c33, -811e3371, -882b0782, -c2840c60, -0882c288, -0c555d52, -59565c80, -0b82c290, -0c9e800b, -82c2940c, -800b82c0, -840c80e4, -51bccb3f, -82c09008, -5574812e, -09810686, -388051b6, -903f82c0, -94085574, -812e0981, -06863874, -51b5fe3f, -805580e9, -397451a2, -e03f8008, -5180c9eb, -3f800853, -745280f5, -a8519e85, -3f7451a2, -b33f8008, -5180c9f9, -3f800853, -745280f5, -bc519ded, -3f7451a4, -bf3f8008, -5180c9e1, -3f800853, -745280f5, -d0519dd5, -3f7451a4, -bc3f8008, -5180c9c9, -3f800853, -745280f5, -e4519dbd, -3f811570, -81ff0651, -55b3a13f, -80087524, -ff8f38a0, -3d0d04f5, -3d0d7e60, -028805b7, -05337154, -5b5b54a1, -f43f8008, -58a85578, -802e8338, -b8557390, -2a7081ff, -06705575, -5480f5f8, -5351579c, -f43f7851, -a1b73f74, -822b82c0, -80118008, -33800881, -05337188, -2b07720c, -82c08413, -80088205, -33800883, -05337198, -2b71902b, -07800884, -05337088, -2b720780, -08850533, -7107760c, -5282c088, -18615a55, -535a4152, -525d5755, -a0d23f80, -0808760c, -82c08c15, -02840580, -c6052271, -0c5482c0, -90157771, -0c5482c0, -94157a08, -710c5682, -c0981502, -840580c2, -05227933, -71902b71, -882b0781, -1c337107, -740c5282, -c09c1882, -1c33831d, +831a3370, +902b7207, +821c3370, +982b7207, +82c2800c, +7c33811e, +3371882b, +0782c284, +0c600882, +c2880c55, +5d525956, +5c800b82, +c2900c9e, +800b82c2, +940c800b, +82c0840c, +80e45180, +c7de3f82, +c0900855, +74812e09, +81068638, +8051b4f9, +3f82c094, +08557481, +2e098106, +86387451, +b4e73f80, +5580e939, +7451a1c9, +3f800851, +80d4fe3f, +80085374, +5280f28c, +519cee3f, +7451a19c, +3f800851, +80d58c3f, +80085374, +5280f2a0, +519cd63f, +7451a3a8, +3f800851, +80d4f43f, +80085374, +5280f2b4, +519cbe3f, +7451a3a5, +3f800851, +80d4dc3f, +80085374, +5280f2c8, +519ca63f, +81157081, +ff065155, +b28a3f80, +087524ff, +8f38a03d, +0d04f53d, +0d7e6002, +8805b705, +3371545b, +5b54a0dd, +3f800858, +a8557880, +2e8338b8, +5573902a, +7081ff06, +70557554, +80f2dc53, +51579bdd, +3f7851a0, +a03f7482, +2b82c080, +11800833, +80088105, +3371882b, +07720c82, +c0841380, +08820533, +80088305, 3371982b, 71902b07, -841f3370, -882b7207, -60850533, -7107760c, -52555555, -40585955, -568d3d0d, -04fb3d0d, -7c567580, -2e9d3884, -16080284, -05ae0522, -56028405, -aa052255, -79545202, -9f053351, -fde53f87, -3d0d04f2, -3d0d655a, -79802e81, -b0388c3d, -5b905379, -527a5180, -dbba3f66, -8f268838, -7b82075c, -80f23979, -08832a70, -81065157, -76802eab, -38881a08, -70942a70, -81065158, -5876802e, -97388280, -80548053, -903dfc05, -5277bfff, -ff0651b9, -c43f8439, +80088405, +3370882b, +72078008, +85053371, +07760c52, +82c08818, +615a5553, +5a415252, +5d57559f, +bb3f8008, +08760c82, +c08c1502, +840580c6, +0522710c, +5482c090, +1577710c, +5482c094, +157a0871, +0c5682c0, +98150284, +0580c205, +22793371, +902b7188, +2b07811c, +33710774, +0c5282c0, +9c18821c, +33831d33, +71982b71, +902b0784, +1f337088, +2b720760, +85053371, +07760c52, +55555540, +58595556, +8d3d0d04, +fb3d0d7c, +5675802e, +9d388416, +08028405, +ae052256, +028405aa, +05225579, +5452029f, +053351fd, +e53f873d, +0d04f23d, +0d655a79, +802e81b2, +388c3d5b, +90537952, +7a5180d9, +d43f668f, +2688387b, +82075c80, +f4397908, +832a7081, +06515776, +802eac38, +881a0870, +942a7081, +06515858, +76802e98, +38828080, +54805390, +3dfc0552, +77bfffff, +065180c4, +d63f8439, 77085f79, 08822a70, 81065157, -76802eac, +76802ead, 38881a08, 70942a70, 81068c1d, 085c5158, 5876802e, -94388280, +95388280, 80548053, 785277bf, ffff0651, -b8a63f84, -3978780c, -79088106, -5776802e, -9c389056, -7a550280, -ce052254, -0280d205, -22536152, -0280c305, -3351a7be, -3f903d0d, -048c0802, -8c0cf03d, -0d8c089c, -05080284, -058c08f8, -050c8c08, -ec050c80, -0b8c08fc, -050c8c08, -ec050880, -2e86cc38, -8c08a005, -088f268b, -38820b8c, -08fc050c, -8681398c, +80c3b73f, +84397878, +0c790881, +06577680, +2e9c3890, +567a5502, +80ce0522, +540280d2, +05225361, +520280c3, +053351a6, +a53f903d, +0d048c08, +028c0cf0, +3d0d8c08, +9c050802, +84058c08, +f8050c8c, +08ec050c, +800b8c08, +fc050c8c, 08ec0508, -0870822a, -70810651, -8c08d405, -0c8c08d8, -050c8c08, -d4050880, -2e9038bb, -fa3f8008, -81068c08, -dc050c85, -bf398c08, -d8050883, +802e86d3, +388c08a0, +05088f26, +8b38820b, +8c08fc05, +0c868839, +8c08ec05, +08087082, 2a708106, 518c08d4, 050c8c08, -d4050880, -2e8738be, -883f85b3, -398c08d8, -0508862a, -70810651, +d8050c8c, +08d40508, +802e9138, +80c78a3f, +80088106, +8c08dc05, +0c85c539, +8c08d805, +08832a70, +8106518c, +08d4050c, 8c08d405, -0c8c08d4, -0508802e, -883880c0, -853f8593, -398c08d8, -0508872a, -70810651, +08802e88, +3880c997, +3f85b839, +8c08d805, +08862a70, +8106518c, +08d4050c, 8c08d405, -0c8c08d4, -0508802e, -9b38bffb, +08802e88, +3880cb94, +3f859839, +8c08d805, +08872a70, +8106518c, +08d4050c, +8c08d405, +08802e9c, +3880cb89, 3f800881, ff068c08, d4050c8c, 08d40508, -822e84e3, -3884d439, +822e84e7, +3884d839, 8c08ec05, 08840508, -51bdcf3f, -80088106, +5180c8dc, +3f800881, +068c08dc, +050c8c08, +dc050880, +2e883881, +0b8c08dc, +050c8c08, +ec050808, +842a7081, +06518c08, +d4050c8c, +08d40508, +802e9838, +8c08dc05, +08802e8f, +3880c8bc, +3f800881, +ff068c08, +dc050c8c, +08ec0508, +8c050870, +9f067030, +72852a71, +9f2a058c, +08e8050c, +518c08d4, +050c8c08, +d8050c80, +708c08e0, +050c8c08, +e4050c8c, +08e40508, +8c08e805, +082781aa, +388c08dc, +05088c08, +e405082e, +819c388c, +08ec0508, +8c05088c, +08e00508, +318c08d8, +050ca00b, +8c08d805, +08278838, +a00b8c08, +d8050c8c, +08d80508, +538c08e0, +0508108c, +08ec0508, +05900552, +8c08ec05, +08880508, +8c08e005, +08051051, +80c2853f, +80088c08, +dc050806, 8c08dc05, 0c8c08dc, 0508802e, 8838810b, 8c08dc05, -0c8c08ec, -05080884, -2a708106, -518c08d4, -050c8c08, -d4050880, -2e97388c, -08dc0508, -802e8e38, -bdb03f80, -0881ff06, -8c08dc05, -0c8c08ec, -05088c05, -08709f06, -70307285, -2a719f2a, -058c08e8, -050c518c, -08d4050c, -8c08d805, -0c80708c, -08e0050c, +0c8c08e0, +05088c08, +d8050805, 8c08e405, +0881058c, +08e4050c, +8c08e005, 0c8c08e4, 05088c08, e8050827, -81a9388c, -08dc0508, -8c08e405, -082e819b, -388c08ec, -05088c05, -088c08e0, -0508318c, +89388c08, +dc0508fe, +e6388c08, +ec050808, +852a7081, +06518c08, +d4050c8c, +08d40508, +802e81f8, +38028c08, +ec05088c, +05087010, +860570fc, +06518c08, +d4050c8c, 08d8050c, -a00b8c08, -d8050827, -8838a00b, -8c08d805, -0c8c08d8, -0508538c, -08e00508, -108c08ec, -05080590, -05528c08, -ec050888, -05088c08, -e0050805, -1051b6fa, -3f80088c, -08dc0508, -068c08dc, -050c8c08, -dc050880, -2e883881, -0b8c08dc, -050c8c08, -e005088c, +8c08f405, +0c028c08, +d4050831, +0d873d8c, 08d80508, -058c08e4, -05088105, -8c08e405, -0c8c08e0, -050c8c08, -e405088c, -08e80508, -2789388c, -08dc0508, -fee7388c, -08ec0508, -08852a70, -8106518c, -08d4050c, -8c08d405, -08802e81, -f738028c, +5470538c, 08ec0508, -8c050870, -10860570, -fc06518c, -08d4050c, -8c08d805, -0c8c08f4, -050c028c, -08d40508, -310d873d, -8c08d805, -08547053, -8c08ec05, -08880508, -10528c08, -f0050cb4, -fe3f8008, +88050810, +528c08f0, +050c80c0, +883f8008, 8c08dc05, 08068c08, dc050c8c, @@ -865,7 +871,7 @@ fc050c8c, 8c088c05, 08528c08, 8b053351, -a0c43f8c, +9fa43f8c, 08f80508, 0d923d0d, 8c0c04f7, @@ -873,8 +879,8 @@ a0c43f8c, 77802eb7, 38770881, 0657768c, -3880f6a0, -5192ae3f, +3880f384, +51918e3f, 78840759, 78820759, 615a8418, @@ -884,417 +890,377 @@ ba052254, 02be0522, 537c5202, af053351, -9ff83f8b, +9ed83f8b, 3d0d04f6, 3d0d7c7e, 59578070, 56567454, 76527753, 8c3df805, -5180cb84, +5180c995, 3f7a8106, 16811656, 56bf7527, e5387580, 0c8c3d0d, -04e63d0d, -eeff3f92, -d3528380, -80519cbb, -3f92a952, +04e73d0d, +eef93f92, +e2528380, +80519b9b, +3f92b852, 83808151, -9cb13f94, -91528380, -85519ca7, -3f9b9352, +9b913f94, +a2528380, +85519b87, +3f9bab52, 83808651, -9c9d3f80, +9afd3f80, 5682c080, 08707731, 51538ad7, -98732785, -9e38805b, -81888808, -9d3dffbc, -055253bf, -b83f8008, -ac140c81, -8888087b, -b0120c53, -8054ba39, -800b8115, -70810654, -75535656, -80c99d3f, -800881ff, -06537276, -2e098106, -83388356, -a8537380, -2e8338b8, -53728429, -82c0b005, -76710c53, -7481ff06, -54a6a53f, -80087424, -ffbe3881, -8fc00881, -11818fc0, -0c538fcf, -732780c3, -38800b81, -8fc00cbc, -b63f8054, -ad397351, -ae803f80, -0881ff06, -5372802e, -91387381, -ff067052, -53beea3f, -725180c6, -883f7381, -ff065180, -c1f33f81, -1454a5d0, -3f800874, -26cc3881, -88880898, -11085454, -72873872, -94150ca0, -39818fc4, -08732e8e, -38810b94, -150c800b, -818fc80c, -8b39818f, -c8088105, -818fc80c, -98140881, -8fc40c8f, -d00b818f, -c8082786, -38800b94, -150c800b, -818fcc0b, -8e3d5a5b, -597881ff, -06558075, -a02982c2, -80055757, -87547570, -84055708, -7705ff15, -55577380, -25f03874, -842982c2, -80055487, -56730877, -05ff17a0, -16565757, -758025f1, -38748126, -8a387451, -96b13f80, -08175777, -08841908, -709f2a72, -10077110, -717c0c70, -841d0c71, -715b5952, -52555376, -7a082e87, -38738107, -73565674, -780c7584, -190c767a, -7084055c, -0c811988, -19595987, -7927fef5, -38818fec, +98732783, +e5388187, +cc089811, +08545472, +87387294, +150ca039, +818f8408, +732e8e38, +810b9415, +0c800b81, +8f880c8b, +39818f88, 08810581, -8fec0c7b, -7d555173, -52fbe83f, -80087e60, -56527453, -55fbdc3f, -8075832b, -818fec08, -bf065656, -58737527, -83388158, -800b8008, -832b5457, -73732783, -38815780, -51abab3f, -800881ff, -06558151, -aba03f80, +8f880c98, +1408818f, +840c8fd0, +0b818f88, +08278638, +800b9415, +0c800b81, +8f8c0b8d, +3d5a5b59, +7881ff06, +558075a0, +2982c280, +05575787, +54757084, +05570877, +05ff1555, +57738025, +f0387484, +2982c280, +05548756, +73087705, +ff17a016, +56575775, +8025f138, +7481268a, +38745196, +ca3f8008, +17577708, +84190870, +9f2a7210, +07711071, +7c0c7084, +1d0c7171, +5b595252, +5553767a, +082e8738, +73810773, +56567478, +0c758419, +0c767a70, +84055c0c, +81198819, +59598779, +27fef538, +818fac08, +8105818f, +ac0c7a7c, +55517352, +fda13f80, +087d7f56, +52745355, +fd953f80, +75832b81, +8fac08bf, +06565658, +73752783, +38815880, +0b800883, +2b545773, +73278338, +81578051, +b7ee3f80, 0881ff06, -81888808, -94110856, -54567380, -2e833881, -54845374, -83387453, -75802e85, -38728807, -5377802e, -85387290, -07538055, -77752e09, -81068638, -76752e83, -38815572, -75075376, +558151b7, +e33f8008, +81ff0681, +87cc0894, +11085654, +5673802e, +83388154, +84537483, +38745375, 802e8538, -72a00753, -73802e85, -38728207, -537282c0, -800c818f, -f0088111, -818ff00c, -5383d4df, -7327b938, -800b818f, -f00c8054, -a6397351, -aaa43f80, -0881ff06, -5372802e, -93387381, -ff067052, -5390cd3f, -80085272, -5195e83f, -811454a1, -fb3f8008, -7426d338, -8051a5d1, -3f8151a5, -cc3f82c0, -8008569c, -c03fb5ea, -3f818888, -08818ff4, +72880753, +77802e85, +38729007, +53805577, +752e0981, +06863876, +752e8338, +81557275, +07537680, +2e853872, +a0075373, +802e8538, +72820753, +7282c080, +0c818fb0, +08811181, +8fb00c53, +83d4df73, +27b93880, +0b818fb0, +0c8054a6, +397351b6, +e73f8008, +81ff0653, +72802e93, +387381ff, +06705253, +90e63f80, +08527251, +96813f81, +1454a294, +3f800874, +26d33880, +51b1fb3f, +8151b1f6, +3f82c080, +08569cd9, +3f80c2ac, +3f8187cc, +08818fb4, 0ba0120c, -8191f40b, +8191b40b, a4120c53, 80c00ba8, 140c83fa, -805181b5, -3f8008ff, -2e80c238, -8193f408, -81057081, -ff067081, -93f40c71, -832b9806, -52565372, -86387281, -93f80c80, -08732b81, -93f80807, -708193f8, -0c7581fc, -06818ff4, -0555740c, -81888808, -7588120c, -538193fc, -08818888, -08545473, -8c14082e, -a9387383, -2b980674, -fc068191, -f4057008, -722a5455, +805181ce, +3f800854, +8008ff2e, +80c43881, +93b40881, +057081ff, +06708193, +b40c7183, +2b980652, +56537286, +38728193, +b80c7373, +2b8193b8, +08077081, +93b80c75, +81fc0681, +8fb40555, +740c8187, +cc087588, +120c53ff, +ad398187, +cc085381, +93bc088c, +14082ebf, +388193bc, +0870832b, +980671fc, +068191b4, +05700872, +2a555255, 5383fa80, -51a93f81, -93fc0881, +51ba3f81, +93bc0881, 057081ff, -068193fc, -0c538188, -8808538c, -8080730c, -f99f3980, -3d0d7274, -710c5182, -3d0d04fe, -3d0d7484, -11535371, -08517080, -2ef9388c, -1376710c, -51843d0d, -04fe3d0d, -74881170, -08515253, -ff527080, -2e873890, -13700853, -5171800c, -843d0d04, -fc3d0d76, -5380fa89, -80527751, -80c4ff3f, -8008ff05, -7083ffff, -067081ff, -06750c70, -882a8416, -0c515481, -800b8814, -0c863d0d, -04fd3d0d, -75787a55, -55528151, -72802e81, -82389012, -0870862a, -70810651, -515170f2, -38029b05, -33701081, -078c140c, -5181900b, -90130c90, -12087081, -2a708106, -51515170, -f2389012, -0870872a, -70810670, -81325151, -51517080, -2eb73872, -802eae38, -80e85172, -812e8338, -a0517090, -130c9012, -0870812a, -70810651, -515170f2, -388c1208, -51707470, -81055634, -ff1353cf, -39815187, -3980c00b, -90130c70, -800c853d, +06708193, +bc0c8187, +cc085651, +53728c15, +082e0981, +06c33881, +87cc0853, +8c808073, +0cfabe39, +803d0d72, +74710c51, +823d0d04, +fe3d0d74, +84115353, +71085170, +802ef938, +8c137671, +0c51843d, +0d04fe3d, +0d748811, +70085152, +53ff5270, +802e8738, +90137008, +53517180, +0c843d0d, +04fc3d0d, +765380fa, +89805277, +5180c4af, +3f8008ff, +057083ff, +ff067081, +ff06750c, +70882a84, +160c5154, +81800b88, +140c863d, 0d04fd3d, 0d75787a, -55555290, +55555281, +5172802e, +81823890, 12087086, 2a708106, 51515170, f238029b, 05337010, -8c140c51, -81d05172, -802e8438, -81905170, +81078c14, +0c518190, +0b90130c, +90120870, +812a7081, +06515151, +70f23890, +12087087, +2a708106, +70813251, +51515170, +802eb738, +72802eae, +3880e851, +72812e83, +38a05170, 90130c90, 12087081, 2a708106, 51515170, -f2389012, -0870872a, -70810670, -81325151, -51517080, -2e80cb38, -72802e80, -c1387333, -8c130c80, -d0517281, -2e833890, -51709013, -0c901208, -70812a70, -81065151, -5170f238, -90120870, -872a7081, -06708132, -51515151, -70802e8e, -388114ff, -145454ff, -bb398151, -893980c0, +f2388c12, +08517074, +70810556, +34ff1353, +cf398151, +873980c0, 0b90130c, -80517080, -0c853d0d, +70800c85, +3d0d04fd, +3d0d7578, +7a555552, +90120870, +862a7081, +06515151, +70f23802, +9b053370, +108c140c, +5181d051, +72802e84, +38819051, +7090130c, +90120870, +812a7081, +06515151, +70f23890, +12087087, +2a708106, +70813251, +51515170, +802e80cb, +3872802e, +80c13873, +338c130c, +80d05172, +812e8338, +90517090, +130c9012, +0870812a, +70810651, +515170f2, +38901208, +70872a70, +81067081, +32515151, +5170802e, +8e388114, +ff145454, +ffbb3981, +51893980, +c00b9013, +0c805170, +800c853d, +0d04f63d, +0d7c7e60, +625a5d5b, +56805981, +55853974, +7a295574, +52755180, +c1a93f80, +087a27ef, +3874802e, +80d83874, +52755180, +c1953f80, +08755376, +525480c1, +af3f8008, +7a537552, +5680c0ff, +3f800879, +30707b07, +9f2a7077, +80240751, +51545572, +85388008, +ca387681, +18b01655, +58588974, +258b38b7, +14537a85, +3880d714, +53727834, +811959ff, +a4398077, +348c3d0d, 04f63d0d, 7c7e6062, 5a5d5b56, 80598155, 8539747a, 29557452, -755180c1, -f93f8008, +755180c0, +a23f8008, 7a27ef38, 74802e80, -d8387452, -755180c1, -e53f8008, +d7387452, +755180c0, +8e3f8008, 75537652, -5480c1ff, +5480c0a8, 3f80087a, 53755256, -80c1cf3f, -80087930, -707b079f, -2a707780, -24075151, -54557285, -388008ca, -38768118, -b0165558, -58897425, -8b38b714, -537a8538, -80d71453, -72783481, -1959ffa4, -39807734, -8c3d0d04, -f63d0d7c, -7e60625a, -5d5b5680, -59815585, -39747a29, -55745275, -5180c0f2, -3f80087a, -27ef3874, -802e80d8, -38745275, -5180c0de, -3f800875, -53765254, -80c0f83f, -80087a53, -75525680, -c0c83f80, +bff93f80, 08793070, 7b079f2a, 70778024, 07515154, 55728538, -8008ca38, +8008cb38, 768118b0, 16555858, 8974258b, @@ -1302,7 +1268,7 @@ c0c83f80, 7a853880, d7145372, 78348119, -59ffa439, +59ffa539, 8077348c, 3d0d04f7, 3d0d7b7d, @@ -1435,7 +1401,7 @@ c139923d, 25555156, 90527984, 1b5b5675, -0851f9e5, +0851f9e6, 3f9f3977, 547b5676, 80d82e09, @@ -1443,7 +1409,7 @@ c139923d, 81567553, 90527984, 1b5b5675, -0851facc, +0851facd, 3f953df4, 05557f54, 96397984, @@ -1460,14 +1426,14 @@ c139923d, 810548fc, 9339953d, 0d047281, -94800c71, -8194840c, +93c00c71, +8193c40c, 04fb3d0d, 883d7070, 84055208, 57547553, -81948008, -52819484, +8193c008, +528193c4, 0851fbd6, 3f873d0d, 04ff3d0d, @@ -1478,8 +1444,8 @@ c139923d, 0c833d0d, 04fc3d0d, 873d8811, -557854ad, -f95351fb, +557854ac, +f15351fb, a93f8052, 873d51d1, 3f863d0d, @@ -1511,8 +1477,8 @@ c53f833d, 54ffab3f, 7351ffb8, 3f8c5373, -527451bf, -833f7480, +527451be, +b43f7480, 0c893d0d, 04fd3d0d, 75705254, @@ -1572,47 +1538,47 @@ ec397180, 7a7c0288, 05b30533, 5b595780, -70819498, +708193d8, 57575484, 53745276, -51bc913f, +51bbc23f, 80089838, 86537752, -73168195, -980551bc, -f33f7881, -96d81534, +73168194, +d80551bc, +a43f7881, +96981534, 80ce3981, 14841685, 18585654, 9f7427cf, 389f0b81, -94940827, +93d40827, 8738800b, -8194940c, -81949408, +8193d40c, +8193d408, 70822b78, -08819498, +088193d8, 120c7110, 05515486, 53775281, -95981451, -bcae3f81, -94940854, -788196d8, +94d81451, +bbdf3f81, +93d40854, +78819698, 15348114, -8194940c, +8193d40c, 8a3d0d04, 803d0d02, 8b053370, 84298196, -f805800c, +b805800c, 51823d0d, 04fe3d0d, 02930533, 70842971, -10058197, -8805800c, +10058196, +c805800c, 52843d0d, 04fa3d0d, 78578054, @@ -1620,19 +1586,19 @@ f805800c, 705255c4, 3f845380, 08527651, -bade3f80, +ba8f3f80, 088a3874, 51c73f80, 0854b739, 81145483, 7427d938, -80708194, -98575754, +80708193, +d8575754, 84537452, -7651bab8, +7651b9e9, 3f80088a, 38731681, -95980554, +94d80554, 91398114, 84168518, 5856549f, @@ -1640,25 +1606,25 @@ bade3f80, 80547380, 0c883d0d, 04ff3d0d, -81949008, +8193d008, 52718726, a838028f, 05335170, -8198b013, +8197f013, 34029305, 33517081, -98b81334, +97f81334, 71842981, -98c00576, +98800576, 710c5181, -12819490, +128193d0, 0c833d0d, 04fe3d0d, -74819488, -0cbba753, +748193c8, +0cba9f53, 80528851, -ffb73fbd, -b3538352, +ffb73fbc, +ab538352, 8351ffad, 3f843d0d, 04fa3d0d, @@ -1667,19 +1633,19 @@ b3538352, 54865379, 52731074, 84290581, -97880551, -ba923f7a, +96c80551, +b9c33f7a, 70088196, -f8170c54, +b8170c54, 7b700881, -97a0170c, +96e0170c, 54800b81, -97c0160c, +9780160c, 883d0d04, 803d0d02, 8b053370, -84298197, -a005800c, +84298196, +e005800c, 51823d0d, 04fd3d0d, 02970533, @@ -1689,8 +1655,8 @@ bb3f8008, d73f7182, 2b800808, 09750781, -97b0120c, -8197b005, +96f0120c, +8196f005, 800c853d, 0d04fb3d, 0d777957, @@ -1698,7 +1664,7 @@ d73f7182, 81ff0651, c43f8453, 74528008, -51b8a53f, +51b7d63f, 8008802e, a3388114, 54837427, @@ -1708,15 +1674,15 @@ fd9b3f80, 802e9938, 86538008, 527551b8, -f33f8b39, +a43f8b39, 865381ff, -527551bb, -c33f8154, +527551b9, +b13f8154, 73800c87, 3d0d04ff, 3d0d028f, 05337084, -298197c0, +29819780, 05700880, 0c525283, 3d0d0480, @@ -1724,14 +1690,14 @@ c33f8154, 33515170, 83268f38, 70842981, -97c00570, +97800570, 08810571, 0c51823d, 0d04f73d, 0d7b7d60, 6373555b, 5b5b55d3, -3f819488, +3f8193c8, 0851f9be, 3f800b80, 08831c82, @@ -1769,7 +1735,7 @@ ff145454, 84291753, 80730c78, 1a185281, -94880851, +93c80851, f8cb3f8b, 3d0d04ec, 3d0d0280, @@ -1777,12 +1743,12 @@ db053358, 778b3d34, 865381ff, 52963dd6, -0551b9b8, +0551b7a6, 3f7751fa, d43f8670, 54800853, 973ddc05, -5257b6c8, +5257b5f9, 3f908602, 8405b605, 23810b90, @@ -1796,15 +1762,15 @@ d43f8670, 7751fa99, 3f765380, 0852963d, -ec0551b6, -8f3f7751, +ec0551b5, +c03f7751, f9f23f84, 53800852, 963df205, -51b5fd3f, +51b5ae3f, 76538052, 963df605, -51b8cd3f, +51b6bb3f, 67700846, 57805680, 55805480, @@ -1812,18 +1778,18 @@ f9f23f84, 3dd00551, fdb43f96, 3d0d04fe, -3d0d8194, -8c085372, +3d0d8193, +cc085372, 8f26a338, 72108197, -d0050284, +90050284, 05920522, 53517171, 23728429, -8197f005, +8197b005, 76710c51, -81138194, -8c0c843d, +81138193, +cc0c843d, 0d04e73d, 0da13d08, a33d08a5, @@ -1835,17 +1801,17 @@ a33d08a5, fbd03f80, 0881ff06, 57768b38, -80f6c851, +80f3ac51, f4a73f81, ee39788e, 3d348653, 77529b3d, ce0551b4, -df3f7851, +903f7851, f8d73f86, 53800852, 9b3dd405, -51b4cd3f, +51b3fe3f, 90800284, 0580c205, 23818a80, @@ -1915,18 +1881,18 @@ bd3f893d, 5b5bf98e, 3f800881, ff065776, -8b3880f7, -8051f1e5, +8b3880f3, +e451f1e5, 3f81b839, 788d3d34, 86537752, 9a3dce05, -51b29d3f, +51b1ce3f, 7851f695, 3f865380, 08529a3d, -d40551b2, -8b3f9080, +d40551b1, +bc3f9080, 028405be, 0523818a, 800b923d, @@ -1972,12 +1938,12 @@ f8d03f9a, 5f5f5877, 912e0981, 0680d238, -800b8194, -8c085b59, +800b8193, +cc085b59, 787a2780, c4388197, -f00b8197, -d05d5b7b, +b00b8197, +905d5b7b, 7082055d, 227d2240, 58777f2e, @@ -1996,7 +1962,7 @@ d05d5b7b, 04df3d0d, 8044a33d, c4055281, -94880851, +93c80851, f0f33f80, 085d8008, 802e8584, @@ -2022,10 +1988,10 @@ f7993f94, 06a43893, 3d598453, a21d5278, -51af893f, +51aeba3f, a13d5886, 539c1d52, -7751aefc, +7751aead, 3f7a5377, 527851f1, d03f861a, @@ -2035,7 +2001,7 @@ d03f861a, 51f2c93f, ac1d5f84, 53800852, -7e51ade0, +7e51ad91, 3f80085c, 800883e4, 387a51f2, @@ -2044,12 +2010,12 @@ c43f8008, 349c1d59, 86537852, a33dce05, -51aeb13f, +51ade23f, 7a51f2a9, 3f865380, 0852a33d, -d40551ae, -9f3f7d02, +d40551ad, +d03f7d02, 840580e2, 05237922, 9b3d2382, @@ -2063,17 +2029,17 @@ d40551ae, 0580ea05, 23865377, 52a33de4, -0551ade4, +0551ad95, 3f847054, 7f53a43d, ea055258, -add63f86, +ad873f86, 537852a3, 3dee0551, -adca3f77, +acfb3f77, 53a21d52, a33df405, -51adbd3f, +51acee3f, 7b567b55, 7b547b53, b052a33d, @@ -2081,7 +2047,7 @@ c80551f5, 853f82c0, 397f51f1, 8b3f7884, -298197f0, +298197b0, 0561f805, 58881c57, 821c2256, @@ -2092,7 +2058,7 @@ c80551f5, 81bd397c, 51f0e13f, 77842981, -98c005f8, +988005f8, 1d58881c, 57861c22, 56841c22, @@ -2123,11 +2089,11 @@ ff065978, 098106bf, 387c3382, 1b22ec05, -81948c08, +8193cc08, 5e424080, 7c279e38, 821b2281, -97d0405e, +9790405e, 7e708205, 40225877, 7e2efeb1, @@ -2135,7 +2101,7 @@ ff065978, 7b7926ec, 38821b22, 537a2252, -80f7b451, +80f49851, eaf73f89, 1a335877, 812e0981, @@ -2143,23 +2109,23 @@ eaf73f89, 7c338c1b, 821c22ec, 055e5f5d, -800b8194, -90085b58, +800b8193, +d0085b58, 777a27aa, 387a3359, -8198b018, +8197f018, 33407860, 2e098106, 9138811b, -338198b8, +338197f8, 1933415f, 7e602efd, fe388118, 58797826, db387a33, -5280f7dc, +5280f4c0, 51ea9e3f, -81948808, +8193c808, 51eb8d3f, a33d0d04, 820b800c, @@ -2208,14 +2174,14 @@ b705338b, 3d348154, 8b3dfc05, 53765277, -51e0a33f, +51e0a43f, 800881ff, 0655ff56, 74802e9e, 3881548b, 3df80553, 76527751, -deef3f80, +def03f80, 0881ff06, 5574802e, 8538893d, @@ -2226,10 +2192,10 @@ deef3f80, 80567980, 2e853883, a0805680, -f7fc51e8, +f4e051e8, 8c3f8176, 0c7981ff, -0680f8a4, +0680f588, 5259e7fd, 3f845481, 53805278, @@ -2279,1451 +2245,1382 @@ c0a45675, 58708206, 70812a56, 58810653, -795280f8, -cc51e6b5, +795280f5, +b051e6b5, 3f8b3d0d, -04f83d0d, -7a5982c0, -a0557880, -2e853882, -c0a45574, -0870832a, -70810651, -56567480, -2e8e3875, -81065378, -5280f98c, -51e6823f, -75842a70, -81065155, -74802e92, -38758206, -70812a54, -55785280, -f9b451e5, -e43f7585, +04fa3d0d, +787a7c80, +f5f05459, +5754e6a1, +3f755280, +f5fc51e6, +983f80f6, +8051e691, +3f73862e, +83df3873, +86269b38, +73812e81, +91388174, +26ad3873, +842e81ff, +3873852e, +82d1388a, +9b397388, +2e85f538, +88742684, +9f387398, +2e888838, +7383ffff, +2e89b638, +89fe3980, +f68451e5, +c83f7652, +80f5fc51, +e5bf3f80, +f68051e5, +b83f8f55, +81752b77, +06547380, +2eb03874, +8f26ab38, +74842981, +83d40554, +73080480, +f6905197, +3980f698, +51913980, +f6a4518b, +3980f6b4, +51853980, +f6cc51e4, +fc3fff15, +55748025, +ffbe3888, +cd3980f6, +dc51e4e9, +3f765280, +f5fc51e4, +e03f80f6, +8051e4d9, +3f8f5581, +752b7706, +5473802e, +b6387482, +2ea03874, +82248838, +74812e9c, +38b93974, +872e0981, +06b13880, +f6e851e4, +ac3f8655, +d23980f6, +f8519839, +80f78451, +e49b3f80, +55c13974, +822e0981, +068d3880, +f79851e4, +883f8155, +ffad39ff, +15557480, +25ffa438, +87d43980, +f7a851e3, +f03f7652, +80f5fc51, +e3e73f80, +f68051e3, +e03f8f55, +81752b77, +06547380, +2ea03874, +802e9438, +807524a0, +38748f24, +9b3880f7, +b851e3bd, +3f923980, +f7cc5183, +bd397488, +3880f7e0, +5183b339, +ff155574, +8025c538, +86fc3980, +f7f851e3, +983f7652, +80f5fc51, +e38f3f80, +f68051e3, +883f8f55, +81752b77, +06547380, +2e80c238, +748726bd, +38748429, +81849405, +54730804, +80f89051, +a93980f8, +a451a339, +80f8a851, +9d3980f8, +b0519739, +80f8b851, +913980f8, +c0518b39, +80f8c851, +853980f8, +d451e2b9, +3fff1555, +748025ff, +ab38868a, +3980f8ec, +51e2a63f, +765280f5, +fc51e29d, +3f80f680, +51e2963f, +8f558175, +2b770654, +73802ebc, +38748e2e, +a038748e, +24883874, +8d2ea138, +ab39748f, +2e098106, +a33880f9, +8851e1e9, +3f8e55d2, +3980f99c, +51e1de3f, +8d55c739, +80f9b051, +e1d33f8c, +55ffbb39, +ff155574, +8025ffb2, +38859f39, +80f9c851, +e1bb3f76, +5280f5fc, +51e1b23f, +80f68051, +e1ab3f75, +812e0981, +0680f038, +768f0654, +738f2684, +f5387384, +298184b4, +05547308, +0480f9d4, +51818f39, +80f9e051, +81883980, +f9ec5181, +813980f9, +fc5180fa, +3980fa88, +5180f339, +80fa9451, +80ec3980, +faa45180, +e53980fa, +b05180de, +3980fac0, +5180d739, +80facc51, +80d03980, +fad85180, +c93980fa, +e45180c2, +3980faf4, +51bc3975, +832e0981, +06848738, +76830654, +73812ea0, +38817426, +a1387382, +2e903873, +832e0981, +0683eb38, +80fb8451, +913980fb, +94518b39, +80fba451, +853980fb, +b451dff5, +3f83cf39, +80fbc451, +dfeb3f76, +5280f5fc, +51dfe23f, +80f68051, +dfdb3f8f, +5581752b, +77065473, +802e81ef, +38748f26, +81e93874, +84298184, +f4055473, +0804768e, +2a813270, +81065154, +73802e81, +ce3880fb, +d05181c4, +3975812e, +09810681, +be3880fb, +e45181b4, +3975812e, +09810681, +ae3880fb, +fc5181a4, +3980fc98, +51819d39, +80fcac51, +81963975, +812e0981, +06819038, +80fcc051, +81863975, +812e0981, +06818038, +80fce051, +80f63975, +812e0981, +0680f038, +80fac051, +80e63975, +812e0981, +0680e038, +80facc51, +80d63975, +812e0981, +0680d038, +80fad851, +80c63975, +812e0981, +0680c038, +80fae451, +b7397581, +2e098106, +b23880fc, +f451a939, +75812e09, +8106a438, +80fd8051, +9b397581, +2e098106, +963880fd, +8c518d39, +75812e09, +81068838, +80f6d051, +dddf3fff, +15557480, +25fdfe38, +81b03980, +fd9851dd, +cc3f7652, +80f5fc51, +ddc33f80, +f68051dd, +bc3f8f55, +81752b77, +06547380, +2eba3874, +8c2680fd, +38748429, +8185b405, +54730804, +80fda851, +9d3980fd, +b8519739, +80fdd851, +913980fd, +e8518b39, +80fdf851, +853980fe, +8851dcf9, +3f80ca39, +74812eb2, +38748124, +88387480, +2eb438b9, +3974822e, +95387483, +2e098106, +ac3880fe, +9851dcd1, +3f8255ff, +933980fe, +ac51dcc5, +3f8155ff, +873980fe, +c051dcb9, +3f7355fe, +fb3980fe, +d451fcb6, +39ff1555, +748025fe, +eb3880fe, +e85180c7, +39765280, +feec51dc, +943f769e, +80067088, +2a545476, +83e08006, +708c2a53, +5480ff88, +51dbfa3f, +768e0670, +812a5354, +80ff9851, +dbeb3f76, +81065473, +802e8838, +80ffa451, +dbdb3f81, +828c51db, +d43fa139, +80ffc051, +dbcb3f73, +5280f5fc, +51dbc23f, +80ffd851, +dbbb3f76, +5280f288, +51dbb23f, +883d0d04, +e53d0d6e, +02840580, +f7053358, +58a45381, +85e8529d, +3dd80551, +9b8f3f89, +3d55a853, +81868c52, +74519b81, +3f81828c, +51dafe3f, +74568955, +77548153, +75085276, +51f0e23f, +80084c6b, +53815275, +70840557, +0851f4ad, +3fff1555, +748025dc, +38933d56, +88557754, +83537508, +527651f0, +b83f8008, +4c6b5383, +52757084, +05570851, +f4833fff, +15557480, +25dc3881, +828c51da, +a43f9d3d, +0d04f93d, +0d795882, +c0a05577, +802e8538, +82c0a455, +74087083, 2a708106, -56577480, -2e923875, -84067082, -2a545578, -5280f9e0, -51e5c63f, -805882c0, -94557881, +51565674, +802e8e38, +75810653, +775280ff, +e851d9f1, +3f75842a, +70810651, +5574802e, +92387582, +0670812a, +54557752, +81809051, +d9d33f75, +852a7081, +06565774, +802e9238, +75840670, +822a5455, +77528180, +bc51d9b5, +3f75b806, +5574802e, +80c63875, +87065574, +bf3882c0, +90557780, 2e853882, -c0905574, +c0945574, 08557481, 2e098106, -83387458, -75b80655, -74802e92, -38758706, -55748b38, -77802e86, -387851fc, -ec3f7681, -06557480, -2e82bd38, -75822a70, -81065155, -74802e8d, -38785280, -fa8851e4, -f03f82a4, -39785280, -fac451e4, -e43f83fc, -80567880, -2e853883, -f8805681, -5182d73f, -835380d0, -527551fb, -d23f800b, -80082481, -e4388008, -81065574, -81cb3880, -08842a70, -81065155, -74802e88, -3880fb84, -5181d639, -8008852a, -70810651, -5574802e, -883880fb, -9c5181c1, -39800886, +a7387751, +f0e33f84, +528051fd, +d33f80e4, +5183a93f, +84528051, +fdc63f80, +e451839c, +3f845280, +51fdb93f, +76810655, +74802e82, +bd387582, 2a708106, 51557480, -2e883880, -fbb45181, -ac398653, +2e8d3877, +528180e4, +51d8c63f, +82a43977, +528181a0, +51d8ba3f, +83fc8056, +77802e85, +3883f880, +56815182, +d73f8353, 80d05275, -51faf83f, +51efa83f, 800b8008, -24818a38, +2481e438, 80088106, -5574802e, -883880fb, -cc518189, -39800881, +557481cb, +38800884, 2a708106, 51557480, -2e883880, -fbec5180, -f4398008, -832a7081, +2e883881, +81e05181, +d6398008, +852a7081, 06515574, 802e8838, -80fc8c51, -80df3988, -5380d052, -7551faab, -3f800b80, -0824be38, -8008822a, -81327081, -06515574, -bc388a53, -80d05275, -51fa8c3f, -800b8008, -249f3880, -08872a70, +8181f851, +81c13980, +08862a70, +81065155, +74802e88, +38818290, +5181ac39, +865380d0, +527551ee, +ce3f800b, +80082481, +8a388008, +81065574, +802e8838, +8182a851, +81893980, +08812a70, 81065155, -74802e9d, -38925380, +74802e88, +388182c8, +5180f439, +8008832a, +70810651, +5574802e, +88388182, +e85180df, +39885380, d0527551, -f9ed3f80, -08802587, -3880fcac, -518b3980, -fccc5185, -3980fcdc, -51e2ca3f, -8198e019, -33568454, -81538152, -7881ff06, -705257f8, -a83f8008, -822a7081, -06515574, -8198e01a, -34759338, -74802e8e, -387651e6, -cb3f8008, -527651eb, -e63f8a3d, -0d04803d, -0d728198, -e0113380, -0c51823d, -0d04fd3d, -0d755480, -53727425, -9b3882c0, -80085282, -c0800870, -73315151, -8ad79771, -27f13881, -1353e239, -853d0d04, -fd3d0d78, -0284059f, -053377bf, -ffff0655, -52547080, -2e863872, -880a0753, -72820a07, -53800b83, -f68c0870, -842a7081, -06515152, -5270722e, -9d388112, -52737227, -85388051, -9d3983f6, -8c087084, -2a708106, -51515170, -e5387683, -f6800c72, -83f6840c, -81517080, -0c853d0d, -04fc3d0d, -777a0288, -05a30533, -79bfffff, -06565356, -5470802e, -86387288, -0a075372, -840a0753, -800b83f6, -8c087084, +ee813f80, +0b800824, +be388008, +822a8132, +70810651, +5574bc38, +8a5380d0, +527551ed, +e23f800b, +8008249f, +38800887, 2a708106, -51515252, -70722e99, -38811252, -717526b7, -3883f68c, +51557480, +2e9d3892, +5380d052, +7551edc3, +3f800880, +25873881, +8388518b, +398183a8, +51853981, +83b851d6, +a03f8198, +a0183356, +84548153, +81527781, +ff067052, +57ebfe3f, +8008822a, +70810651, +55748198, +a0193475, +93387480, +2e8e3876, +51daa13f, +80085276, +51dfbc3f, +893d0d04, +803d0d72, +8198a011, +33800c51, +823d0d04, +fd3d0d75, +54805372, +74259b38, +82c08008, +5282c080, +08707331, +51518ad7, +977127f1, +38811353, +e239853d, +0d04fd3d, +0d780284, +059f0533, +77bfffff, +06555254, +70802e86, +3872880a, +07537282, +0a075380, +0b83f68c, 0870842a, 70810651, -515170e9, -3873802e, -84388074, +51525270, +722e9d38, +81125273, +72278538, +80519d39, +83f68c08, +70842a70, +81065151, +5170e538, +7683f680, 0c7283f6, -840c800b, +840c8151, +70800c85, +3d0d04fc, +3d0d777a, +028805a3, +053379bf, +ffff0656, +53565470, +802e8638, +72880a07, +5372840a, +0753800b, 83f68c08, -70810651, +70842a70, +81065151, 52527072, 2e993881, -12527472, -27853880, -519a3983, +12527175, +26b73883, f68c0870, -81065151, +842a7081, +06515151, 70e93873, -802e8738, -83f68808, -740c8151, -70800c86, -3d0d04f6, -3d0d7d7f, -5a5a817d, -9fffff06, -98808007, -59578056, -757927af, -38751655, -82808054, -81538c3d, -fc055274, -1851feb9, -3f800881, -ff067a16, -565702aa, -05227523, -81165675, -79278438, -76d33876, -800c8c3d, -0d04f63d, -0d7d7f71, -30707307, -80257073, -a0260751, -5157595a, -80567476, -2e098106, -81ee3882, -80805481, -5381aa52, -888851fd, -833f8008, -81ff0656, -82808054, -815380d5, -52888051, -fcee3f80, -08760656, -75802eb1, +802e8438, +80740c72, +83f6840c, +800b83f6, +8c087081, +06515252, +70722e99, +38811252, +74722785, +3880519a, +3983f68c, +08708106, +515170e9, +3873802e, +873883f6, +8808740c, +81517080, +0c863d0d, +04f63d0d, +7d7f5a5a, +817d9fff, +ff069880, +80075957, +80567579, +27af3875, +16558280, +80548153, +8c3dfc05, +52741851, +feb93f80, +0881ff06, +7a165657, +02aa0522, +75238116, +56757927, +843876d3, +3876800c, +8c3d0d04, +f63d0d7d, +7f713070, +73078025, +7073a026, +07515157, +595a8056, +74762e09, +810681ee, 38828080, -548153a5, -52988080, -51fcd53f, +54815381, +aa528888, +51fd833f, 800881ff, +06568280, +80548153, +80d55288, +8051fcee, +3f800876, 06567580, -2e973882, +2eb13882, 80805481, -53ff1852, -98808051, -fcba3f80, -0881ff06, -567c9fff, -ff069880, -80075980, -57767827, -a8387580, -2e9e3876, -177a1170, -22515755, -82808054, -81537552, -741951fc, -873f8008, +53a55298, +808051fc, +d53f8008, 81ff0656, -811757d5, -3975802e, -96388280, -80548153, -a9529880, -8051fbe8, +75802e97, +38828080, +548153ff, +18529880, +8051fcba, 3f800881, -ff065677, -18558280, +ff06567c, +9fffff06, +98808007, +59805776, +7827a838, +75802e9e, +3876177a, +11702251, +57558280, 80548153, -8c3dfc05, -527419fe, -0551fcb1, -3f800876, -06567580, -2e9e3881, -7a160288, -05aa0522, -fe122270, -7232872a, -70750651, -51525956, -5674c438, -75800c8c, -3d0d04f7, -3d0d8280, -80548053, -81a9ec52, -81c051fb, -f03f8280, -80548053, -81a9e852, -81e051fb, -e03f8158, +75527419, +51fc873f, +800881ff, +06568117, +57d53975, +802e9638, 82808054, -80539881, -915281c0, -51fae93f, -80087806, -5776802e, -83387757, +8153a952, +98808051, +fbe83f80, +0881ff06, +56771855, 82808054, -8053fdf5, -b6fdef52, -848051fa, -cb3f8008, -81ff0677, -06577680, -2e833877, -57828080, -54775381, -acf85284, -8451faac, -3f800881, -ff067706, -5776802e, -83387757, -8a3d5982, -80805477, -53785280, -51faf23f, +81538c3d, +fc055274, +19fe0551, +fcb13f80, +08760656, +75802e9e, +38817a16, +028805aa, +0522fe12, +22707232, +872a7075, +06515152, +59565674, +c4387580, +0c8c3d0d, +04f73d0d, +82808054, +80538199, +d45281c0, +51fbf03f, +82808054, +80538199, +d05281e0, +51fbe03f, +81588280, +80548053, +98819152, +81c051fa, +e93f8008, +78065776, +802e8338, +77578280, +80548053, +fdf5b6fd, +ef528480, +51facb3f, 800881ff, 06770657, 76802e83, 38775782, 80805477, -53795284, -8651f9f0, -3f800881, -ff067706, -5776802e, -83387757, -82808054, -80537852, -848051fa, -b83f8008, +5381acf8, +52848451, +faac3f80, +0881ff06, +77065776, +802e8338, +77578a3d, +59828080, +54775378, +528051fa, +f23f8008, 81ff0677, 06577680, 2e833877, -5779fdf5, -b6fdef32, -70307072, -07700970, -9f2c7c06, -5c515157, -55828080, -54805378, -52848451, -fa833f80, +57828080, +54775379, +52848651, +f9f03f80, 0881ff06, 77065776, 802e8338, -81577781, -06587987, -d6c1acf8, -2e833880, -58805576, -802e8838, -77802e83, -38815574, -81ff0680, -0c8b3d0d, -04fd3d0d, -82808054, -805381a9, -ec085281, -c051f8d4, -3f828080, -54805381, -a9e80852, -81e051f8, -c33f853d, -0d04fc3d, -0d76912b, -55828080, -54805374, -5281e051, -f8aa3f80, -0881ff06, -800c863d, -0d04fa3d, -0d828080, -54815381, -aa528888, -51f88d3f, +77578280, +80548053, +78528480, +51fab83f, 800881ff, -06557480, -2e81b038, -82808054, -815380d5, -52888051, -f7f23f80, -0881ff06, -5574802e, -81953882, +06770657, +76802e83, +38775779, +fdf5b6fd, +ef327030, +70720770, +09709f2c, +7c065c51, +51575582, +80805480, +53785284, +8451fa83, +3f800881, +ff067706, +5776802e, +83388157, +77810658, +7987d6c1, +acf82e83, +38805880, +5576802e, +88387780, +2e833881, +557481ff, +06800c8b, +3d0d04fd, +3d0d8280, +80548053, +8199d408, +5281c051, +f8d43f82, +80805480, +538199d0, +085281e0, +51f8c33f, +853d0d04, +fc3d0d76, +912b5582, +80805480, +53745281, +e051f8aa, +3f800881, +ff06800c, +863d0d04, +fa3d0d82, 80805481, -53818052, -888851f7, -d73f8008, +5381aa52, +888851f8, +8d3f8008, 81ff0655, -74802e80, -fa388280, +74802e81, +b0388280, 80548153, -81aa5288, -8851f7bc, +80d55288, +8051f7f2, 3f800881, ff065574, -802e80df, +802e8195, 38828080, -54815380, -d5528880, -51f7a13f, +54815381, +80528888, +51f7d73f, 800881ff, 06557480, -2e80c438, +2e80fa38, 82808054, -8153b052, -98808051, -f7863f80, +815381aa, +52888851, +f7bc3f80, 0881ff06, 5574802e, -aa388280, +80df3882, +80805481, +5380d552, +888051f7, +a13f8008, +81ff0655, +74802e80, +c4388280, 80548153, -883dfc05, -52988080, -51f7ce3f, -800881ff, -06028405, -9a052257, -557583ff, -ff2e0981, -06d33874, -800c883d, -0d04fd3d, -0d828080, -54805381, -5280d851, -f6ba3f85, -3d0d04fa, -3d0d8280, -80548053, -883dfc05, -5280d851, -f7873f80, -08810655, -83567480, -2e863802, -9b053356, -75800c88, -3d0d04fe, -3d0d800b, -83f68c08, -70842a70, -81065151, -52527072, -2ea23881, -a9f00853, -81125272, -72278538, -80519f39, -83f68c08, -70842a70, -81065151, -5170e538, -7483f680, -0c810a0b, -83f6840c, -81517080, -0c843d0d, +b0529880, +8051f786, +3f800881, +ff065574, +802eaa38, +82808054, +8153883d, +fc055298, +808051f7, +ce3f8008, +81ff0602, +84059a05, +22575575, +83ffff2e, +098106d3, +3874800c, +883d0d04, +fd3d0d82, +80805480, +53815280, +d851f6ba, +3f853d0d, +04fa3d0d, +82808054, +8053883d, +fc055280, +d851f787, +3f800881, +06558356, +74802e86, +38029b05, +33567580, +0c883d0d, 04fe3d0d, -7483f68c, -0870812a, -70810651, -51525370, -802e80e4, -3880d5ff, -0b81aa84, -0c83f680, -0881a9fc, -0c83f684, -0870bfff, -ff0681a9, -f80c709c, +800b83f6, +8c087084, 2a708106, -51525270, -81aa8034, -719d2a70, -81065151, -70802e89, -38810b81, -a9f4349b, -39719e2a, -70810651, -5170802e, -8938820b, -81a9f434, -86397081, -a9f43481, -a9f4730c, -81518439, -70730c70, -800c843d, -0d04fb3d, -0d873dfc, -0551fef1, -3f800881, -ff065372, -802e80c5, -38758c11, -33545572, -bc387433, -5372822e, -0981068e, -38841508, -88160871, -0c548153, -a6397281, -2e098106, -9c388415, -08700851, -53828080, -52725190, -15085372, -2d800881, -ff065383, -39805372, -800c873d, -0d04f93d, -0d797b57, -57807056, -5474802e, -8a387514, -51ba7134, -81145475, -14751870, -3370842a, -545a5452, -8186f011, +51515252, +70722ea2, +388199d8, +08538112, +52727227, +85388051, +9f3983f6, +8c087084, +2a708106, +51515170, +e5387483, +f6800c81, +0a0b83f6, +840c8151, +70800c84, +3d0d04fe, +3d0d7483, +f68c0870, +812a7081, +06515152, +5370802e, +80e43880, +e1a10b81, +99ec0c83, +f6800881, +99e40c83, +f6840870, +bfffff06, +8199e00c, +709c2a70, +81065152, +52708199, +e834719d, +2a708106, +51517080, +2e893881, +0b8199dc, +349b3971, +9e2a7081, +06515170, +802e8938, +820b8199, +dc348639, +708199dc, +348199dc, +730c8151, +84397073, +0c70800c, +843d0d04, +fb3d0d87, +3dfc0551, +fef13f80, +0881ff06, +5372802e, +80c53875, +8c113354, +5572bc38, +74335372, +822e0981, +068e3884, +15088816, +08710c54, +8153a639, +72812e09, +81069c38, +84150870, +08515382, +80805272, +51901508, +53722d80, +0881ff06, +53833980, +5372800c, +873d0d04, +f93d0d79, +7b575780, +70565474, +802e8a38, +751451ba, +71348114, +54751475, +18703370, +842a545a, +54528186, +b4113372, +34811476, +1174338f, +06535354, +8186b411, 33723481, -14761174, -338f0653, -53548186, -f0113372, -34811481, -16565485, -7527c238, -75145180, -71347580, +14811656, +54857527, +c2387514, +51807134, +75800c89, +3d0d04f9, +3d0d797b, +83123358, +82123357, +81123356, +71335581, +86c45470, +535957c8, +bc3f7780, 0c893d0d, -04f93d0d, -797b8312, -33588212, -33578112, -33567133, -55818780, -54705359, -57d4e63f, -77800c89, +04fe3d0d, +8198a408, +81058306, +708198a4, +0c701011, +70882981, +98a80554, +51537451, +fee23f84, 3d0d04fe, -3d0d8198, -e4088105, +3d0d8199, +88088105, 83067081, -98e40c70, -10117088, -298198e8, -05545153, -7451fee2, +99880c70, +90298199, +8c055353, +7451ff97, 3f843d0d, -04fe3d0d, -8199c808, -81058306, -708199c8, -0c709029, -8199cc05, -53537451, -ff973f84, -3d0d04ff, -3d0d819a, -8c228105, -5170819a, -8c23833d, -0d04fe3d, -0d745180, -52881108, -802e9b38, -819a8c22, -82122271, -71317083, -ffff0651, -51525370, -82268338, -81527181, -ff06800c, -843d0d04, -ff3d0d73, -75982b70, -982c5153, -51029605, -22712381, -9a8c2282, -12237184, -12347670, -0888130c, -52833d0d, -04f53d0d, -7d7f6362, -982b7098, -2c029405, -80c20522, -5f515e5e, -59598057, -76782780, -de387856, -7551fefe, -3f800881, -ff065574, -802eb638, -8816087c, -082e0981, -06b53884, -1633557a, -752e0981, -06a93875, -22558057, -79752e8e, -38797531, -902b5576, -75248338, -81577655, -74802eb6, -387b5479, -537a5275, -51a73981, -178c1757, -57777726, -ffa63877, -10187084, -29f40554, -5578528c, -195193c5, -3f7b5479, -537a5278, -51febd3f, -81577680, -0c8d3d0d, -04803d0d, -72518180, -710c81a1, -d40b800c, -823d0d04, -fe3d0d74, -81a1d452, -5380ff52, -70087308, -2e098106, -89388071, -0c800b84, -120cff12, -88125252, -718025e4, -38843d0d, -04f63d0d, -02b30533, -70525bd7, -ec3f8058, -80578008, -56819a90, -2281115a, -5a78819a, -90237983, -ffff0655, -84805480, -538f527a, -51dc833f, -8c3d0d04, -f33d0d7f, -61636573, -1270335b, -595e5f5d, -5e7580dc, -38817534, -7581a1d8, -0b81a1d4, -5a5a5a7d, -822b1c78, -08881a5a, -56567476, -082e0981, -06ad3880, -56757b27, -a6387b57, -76708405, -58085574, -79082e09, -81068c38, -7a547c53, -7b527551, -ffa63f81, -16567a76, -26de3881, -1a881a5a, -5a80ff7a, -27ffb438, -8f3d0d04, -fed43d0d, -81af3d08, -5d807081, -a1d40bb1, -3d5f5b5c, -57780855, -74802eb3, -38841908, -802eac38, -80567577, -279a3874, -af3d5b58, -79708405, -5b085574, -782e9438, -81165676, -7626ed38, -78087c70, -84055e0c, -81175781, -1b881a5a, -5b80ff7b, -27ffba38, -80567577, -2792388e, -3d587518, -55807534, -81165676, -7626f338, -80567577, -27ae38ae, -3d587770, -84055908, -55747d08, -2e098106, -93387654, -81ae3dfb, -801154fc, -80055275, -51fded3f, -81165676, -7626d738, -80567577, -27b53881, -b03d0870, -08903db1, -3d5c5c59, -55787084, -055a0855, -74782e09, -81069038, -751a7033, -51557480, -2e853881, -558b3981, -16567676, -26db3880, -5574800c, -81ae3d0d, -04fb3d0d, -029f0533, -568055b0, -3975752e, -a8387582, -2b81a9d4, -05751176, -81ff0653, -5153d284, -3f800876, -5254d1fc, -3f735280, -0851fde0, -3f800873, -34811555, -e3a63f80, -087526c9, -38873d0d, -04ef3d0d, -65028405, -80cf0533, -02880580, -d2052288, -13705971, -5872982b, -70982c58, -5d404242, -5e80c052, -819bd451, -fa8f3f80, -0881ff06, -5978802e, -82bb3881, -9bdc5cbf, -0b819bd4, -5b5b881a, -08802e9e, -38819a8c, -22821b22, -71713170, -83ffff06, -515b435f, -82792786, -387b51fb, -8b3fff1b, -8c1b8c1e, -5e5b5b7a, -8025cf38, -7c51faf8, -3f80705a, -5f9a3978, -81ff0651, -d0d63f88, -1e088008, -082e0981, -06833881, -5f811959, -e1fe3f80, -087926df, -38805c7d, -087c2e80, -d9388c1e, -5b7e802e, -8838841e, -087c26bd, -38800b81, -a1d45a5a, -78088c38, -7c08790c, -7a08841a, -0ca73981, -1a881a5a, -5a80ff7a, -27e63887, -f85381a1, -d45281a1, -dc518da5, -3f7c0881, -a1d40c7a, -0881a1d8, -0c811c84, -1c5c5c7d, -087c26ff, -ac38819a, -9c0bfc11, -5b5b805d, -8f5c7c84, -29819a94, -05598819, -08881f08, -2ebc3878, -51f7bb3f, -800881ff, -06597880, -2eac3879, -3351e8ea, -3f800881, -ff065978, -802e9b38, -7d088429, -8c05587d, -577a567f, -55848154, -80538f52, -793351d5, -f93fff1c, -831e8c1c, -8c1e5e5c, -5e5c7b80, -25ffa338, -6051fcc5, -3f933d0d, -04f53d0d, -62028405, -b7053302, -880580c2, -0522028c, -0580c605, -225d5b5d, -5b788480, -2e893878, -84812e98, -389f3963, -587a577e, -56795578, -54805390, -527b51d5, -a13f8a39, -7a537952, -7b51fcc1, -3f8d3d0d, -04fdf73d, -0d0288af, -05335a80, -5981c239, -8b3d5588, -80538052, -74518cf4, -3f7881ff, -0651cdf8, -3f800808, -5d80750c, -805c8056, -ad397876, -2ea53874, -08842915, -8c117781, -ff065376, -08810577, -0c5154cd, -cf3f8008, -08740c84, -15088105, -84160c81, -1656def8, -3f800876, -26cc3880, -0b819a94, -57587408, -822b9011, -55577387, -ff26b938, -7551f59e, -3f800881, -ff065473, -802e9d38, -84163354, -78742e09, -81069138, -74178c05, -88170871, -0c547408, -8105750c, -81188c17, -57588f78, -27ffbb38, -7453819a, -90228111, -55557381, -9a902374, -83ffff06, -527951fa, -f03f8119, -59de853f, -80087926, -feb63882, -8b3d0d04, -fa3d0d02, -a3053302, -8405ae05, -22575775, -84802e09, -8106a938, -795502b2, -05225476, -982b7098, -2c545690, -52819a94, -51f4ea3f, -800881ff, -06567580, -2e863876, -51fde23f, -883d0d04, -ff3d0d02, -8f053370, -842981a9, -d4050288, -05930533, -71057033, -800c5152, -52833d0d, -04fa3d0d, -80e3a553, -80528f51, -ccdb3f80, -e5d05380, -529051cc, -d03f800b, -81a9d457, -57805574, -16548174, -34811555, -837527f3, -38811784, -17575783, -7727e638, -883d0d04, -8c08028c, -0cf53d0d, -8c089405, -089d388c, -088c0508, -8c089005, -088c0888, -05085856, -5473760c, -7484170c, -81bf3980, -0b8c08f0, -050c800b, -8c08f405, -0c8c088c, +048c0802, +8c0cf53d, +0d8c0894, +05089d38, +8c088c05, +088c0890, 05088c08, -90050856, -54738c08, -f0050c74, -8c08f405, -0c8c08f8, -058c08f0, -05565688, -70547553, -76525486, -cb3fa00b, -8c089405, -08318c08, -ec050c8c, -08ec0508, -80249d38, +88050858, +56547376, +0c748417, +0c81bf39, 800b8c08, -f0050c8c, -08ec0508, -308c08f8, -0508712a, -8c08f405, -0c54b939, -8c08f805, -088c08ec, -05082b8c, -08e8050c, -8c08f805, -088c0894, -05082a8c, +f0050c80, +0b8c08f4, +050c8c08, +8c05088c, +08900508, +5654738c, 08f0050c, -8c08fc05, -088c0894, -05082a70, +748c08f4, +050c8c08, +f8058c08, +f0055656, +88705475, +53765254, +86cb3fa0, +0b8c0894, +0508318c, +08ec050c, +8c08ec05, +0880249d, +38800b8c, +08f0050c, +8c08ec05, +08308c08, +f8050871, +2a8c08f4, +050c54b9, +398c08f8, +05088c08, +ec05082b, 8c08e805, -08078c08, -f4050c54, +0c8c08f8, +05088c08, +9405082a, 8c08f005, -088c08f4, +0c8c08fc, 05088c08, -88050858, -56547376, -0c748417, -0c8c0888, -0508800c, -8d3d0d8c, -0c048c08, -028c0cfd, -3d0d8053, -8c088c05, -08528c08, -88050851, -82de3f80, -0870800c, -54853d0d, +9405082a, +708c08e8, +0508078c, +08f4050c, +548c08f0, +05088c08, +f405088c, +08880508, +58565473, +760c7484, +170c8c08, +88050880, +0c8d3d0d, 8c0c048c, 08028c0c, -fd3d0d81, +fd3d0d80, 538c088c, 0508528c, 08880508, -5182b93f, +5182de3f, 80087080, 0c54853d, 0d8c0c04, 8c08028c, -0cf93d0d, +0cfd3d0d, +81538c08, +8c050852, +8c088805, +085182b9, +3f800870, +800c5485, +3d0d8c0c, +048c0802, +8c0cf93d, +0d800b8c, +08fc050c, +8c088805, +088025ab, +388c0888, +0508308c, +0888050c, 800b8c08, +f4050c8c, +08fc0508, +8838810b, +8c08f405, +0c8c08f4, +05088c08, fc050c8c, -08880508, +088c0508, 8025ab38, -8c088805, +8c088c05, 08308c08, -88050c80, -0b8c08f4, +8c050c80, +0b8c08f0, 050c8c08, fc050888, 38810b8c, -08f4050c, -8c08f405, +08f0050c, +8c08f005, 088c08fc, +050c8053, +8c088c05, +08528c08, +88050851, +81a73f80, +08708c08, +f8050c54, +8c08fc05, +08802e8c, +388c08f8, +0508308c, +08f8050c, +8c08f805, +0870800c, +54893d0d, +8c0c048c, +08028c0c, +fb3d0d80, +0b8c08fc, 050c8c08, -8c050880, -25ab388c, -088c0508, -308c088c, -050c800b, -8c08f005, -0c8c08fc, -05088838, -810b8c08, -f0050c8c, -08f00508, +88050880, +2593388c, +08880508, +308c0888, +050c810b, 8c08fc05, -0c80538c, +0c8c088c, +05088025, +8c388c08, +8c050830, +8c088c05, +0c81538c, 088c0508, 528c0888, -05085181, -a73f8008, -708c08f8, -050c548c, -08fc0508, -802e8c38, +050851ad, +3f800870, 8c08f805, -08308c08, -f8050c8c, +0c548c08, +fc050880, +2e8c388c, 08f80508, -70800c54, -893d0d8c, -0c048c08, -028c0cfb, -3d0d800b, -8c08fc05, -0c8c0888, -05088025, -93388c08, -88050830, -8c088805, -0c810b8c, +308c08f8, +050c8c08, +f8050870, +800c5487, +3d0d8c0c, +048c0802, +8c0cfd3d, +0d810b8c, 08fc050c, -8c088c05, -0880258c, -388c088c, -0508308c, -088c050c, -81538c08, -8c050852, +800b8c08, +f8050c8c, +088c0508, 8c088805, -0851ad3f, -8008708c, -08f8050c, -548c08fc, -0508802e, -8c388c08, -f8050830, -8c08f805, -0c8c08f8, -05087080, -0c54873d, -0d8c0c04, -8c08028c, -0cfd3d0d, -810b8c08, -fc050c80, -0b8c08f8, +0827ac38, +8c08fc05, +08802ea3, +38800b8c, +088c0508, +2499388c, +088c0508, +108c088c, 050c8c08, -8c05088c, -08880508, -27ac388c, +fc050810, +8c08fc05, +0cc9398c, 08fc0508, -802ea338, -800b8c08, -8c050824, -99388c08, -8c050810, -8c088c05, -0c8c08fc, -0508108c, -08fc050c, -c9398c08, -fc050880, -2e80c938, -8c088c05, -088c0888, -050826a1, -388c0888, -05088c08, -8c050831, -8c088805, -0c8c08f8, +802e80c9, +388c088c, 05088c08, -fc050807, +88050826, +a1388c08, +8805088c, +088c0508, +318c0888, +050c8c08, +f805088c, +08fc0508, +078c08f8, +050c8c08, +fc050881, +2a8c08fc, +050c8c08, +8c050881, +2a8c088c, +050cffaf, +398c0890, +0508802e, +8f388c08, +88050870, +8c08f405, +0c518d39, 8c08f805, -0c8c08fc, -0508812a, -8c08fc05, -0c8c088c, -0508812a, -8c088c05, -0cffaf39, -8c089005, -08802e8f, -388c0888, -0508708c, -08f4050c, -518d398c, -08f80508, -708c08f4, -050c518c, -08f40508, -800c853d, -0d8c0c04, -fc3d0d78, -77795656, -52837227, -8c387474, -07830651, -70802eb0, -38ff1252, -71ff2ea0, -38743374, -33525372, -712e0981, -06bd3881, -158115ff, -14545555, -71ff2e09, -8106e238, -800b800c, -863d0d04, -74745451, -70087308, -2e098106, -8f388411, -8414fc14, -54545171, -8326e938, -70735555, -ffaf3972, -7131800c, -863d0d04, -fc3d0d76, -70797b55, -5555558f, -72278c38, -72750783, -06517080, -2ea738ff, -125271ff, -2e983872, -70810554, -33747081, -055634ff, -125271ff, -2e098106, -ea387480, +08708c08, +f4050c51, +8c08f405, +08800c85, +3d0d8c0c, +04fc3d0d, +78777956, +56528372, +278c3874, +74078306, +5170802e, +b038ff12, +5271ff2e, +a0387433, +74335253, +72712e09, +8106bd38, +81158115, +ff145455, +5571ff2e, +098106e2, +38800b80, 0c863d0d, -04745172, -70840554, -08717084, -05530c72, -70840554, -08717084, -05530c72, -70840554, -08717084, -05530c72, -70840554, -08717084, -05530cf0, -1252718f, -26c93883, -72279538, +04747454, +51700873, +082e0981, +068f3884, +118414fc, +14545451, +718326e9, +38707355, +55ffaf39, +72713180, +0c863d0d, +04fc3d0d, +7670797b, +55555555, +8f72278c, +38727507, +83065170, +802ea738, +ff125271, +ff2e9838, +72708105, +54337470, +81055634, +ff125271, +ff2e0981, +06ea3874, +800c863d, +0d047451, 72708405, 54087170, 8405530c, -fc125271, -8326ed38, -7054ff83, -39fa3d0d, -787a7c72, -72725757, -57595656, -747627b2, -38761551, -757127aa, -38707717, -ff145455, -5371ff2e, -9638ff14, -ff145454, -72337434, +72708405, +54087170, +8405530c, +72708405, +54087170, +8405530c, +72708405, +54087170, +8405530c, +f0125271, +8f26c938, +83722795, +38727084, +05540871, +70840553, +0cfc1252, +718326ed, +387054ff, +8339fc3d, +0d767971, +028c059f, +05335755, +53558372, +278a3874, +83065170, +802ea238, ff125271, -ff2e0981, -06ec3875, -800c883d, -0d04768f, -269738ff, +ff2e9338, +73737081, +055534ff, 125271ff, -2eed3872, -70810554, -33747081, -055634eb, -39747607, -83065170, -e2387575, -54517270, -84055408, -71708405, -530c7270, -84055408, -71708405, -530c7270, -84055408, -71708405, -530c7270, -84055408, +2e098106, +ef387480, +0c863d0d, +04747488, +2b750770, +71902b07, +5154518f, +7227a538, +72717084, +05530c72, 71708405, -530cf012, -52718f26, -c9388372, -27953872, -70840554, -08717084, -05530cfc, -12527183, -26ed3870, -54ff8839, -fc3d0d76, -7971028c, -059f0533, -57555355, -8372278a, -38748306, -5170802e, -a238ff12, -5271ff2e, -93387373, -70810555, -34ff1252, -71ff2e09, -8106ef38, -74800c86, -3d0d0474, -74882b75, -07707190, -2b075154, -518f7227, -a5387271, +530c7271, 70840553, 0c727170, 8405530c, -72717084, -05530c72, -71708405, -530cf012, -52718f26, -dd388372, -27903872, -71708405, -530cfc12, -52718326, -f2387053, -ff9039fd, -3d0d800b, -8187b008, -54547281, -2e9d3873, -81a9e40c, -ff96b93f, -ff95d53f, -81888c52, -8151ffa9, -d03f8008, -51a33f72, -81a9e40c, -ff969d3f, -ff95b93f, -81888c52, -8151ffa9, -b43f8008, -51873f00, -ff3900ff, -39f73d0d, -7b818890, -0882c811, -085a545a, -77802e80, -da388188, -18841908, -ff058171, -2b595559, -80742480, -ea388074, -24b53873, -822b7811, -88055656, -81801908, -77065372, -802eb638, -78167008, -53537951, -74085372, -2dff14fc, -17fc1779, -812c5a57, -57547380, -25d63877, -085877ff, -ad388188, -900853bc, -1308a538, -7951ff83, -3f740853, -722dff14, -fc17fc17, -79812c5a, -57575473, -8025ffa8, -38d13980, -57ff9339, -7251bc13, +f0125271, +8f26dd38, +83722790, +38727170, +8405530c, +fc125271, +8326f238, +7053ff90, +39fd3d0d, +800b8186, +f4085454, +72812e9d, +38738199, +cc0cff99, +d33fff98, +ef3f8187, +d0528151, +ffad823f, +800851a3, +3f728199, +cc0cff99, +b73fff98, +d33f8187, +d0528151, +fface63f, +80085187, +3f00ff39, +00ff39f7, +3d0d7b81, +87d40882, +c811085a, +545a7780, +2e80da38, +81881884, +1908ff05, +81712b59, +55598074, +2480ea38, +807424b5, +3873822b, +78118805, +56568180, +19087706, +5372802e, +b6387816, +70085353, +79517408, +53722dff, +14fc17fc, +1779812c, +5a575754, +738025d6, +38770858, +77ffad38, +8187d408, +53bc1308, +a5387951, +ff833f74, 0853722d, -7951fed7, -3fff3d0d, -818f940b, -fc057008, -525270ff, -2e913870, -2dfc1270, -08525270, -ff2e0981, -06f13883, -3d0d0404, -ff95a23f, -04000000, +ff14fc17, +fc177981, +2c5a5757, +54738025, +ffa838d1, +398057ff, +93397251, +bc130853, +722d7951, +fed73fff, +3d0d818e, +d80bfc05, +70085252, +70ff2e91, +38702dfc, +12700852, +5270ff2e, +098106f1, +38833d0d, +0404ff98, +bc3f0400, 00000040, 00000000, 58333030, @@ -3875,129 +3772,6 @@ ff95a23f, 4f444142, 533a2025, 640a0000, -44454255, -473a2065, -74682531, -64205258, -4c4f5320, -6368616e, -67656420, -73746174, -653a2025, -640a0000, -44454255, -473a2065, -74682531, -64205458, -4641554c, -54206368, -616e6765, -64207374, -6174653a, -2025640a, -00000000, -44454255, -473a2065, -74682531, -64204d4f, -44414253, -20636861, -6e676564, -20737461, -74653a20, -25640a00, -494e464f, -3a20416e, -20534650, -2b206d6f, -64756c65, -20686173, -20626565, -6e207265, -6d6f7665, -64206672, -6f6d2065, -74682070, -6f727420, -25642e0a, -00000000, -494e464f, -3a204120, -6e657720, -5346502b, -206d6f64, -756c6520, -68617320, -6265656e, -20696e73, -65727465, -6420696e, -746f2065, -74682070, -6f727420, -25642e0a, -00000000, -44454255, -473a2053, -4646505f, -54595045, -5f53522e, -0a000000, -44454255, -473a2053, -4646505f, -54595045, -5f4c522e, -0a000000, -44454255, -473a2053, -4646505f, -54595045, -5f4c524d, -2e0a0000, -44454255, -473a2053, -4646505f, -54595045, -5f313030, -30424153, -455f5358, -2e0a0000, -44454255, -473a2053, -4646505f, -54595045, -5f313030, -30424153, -455f4c58, -2e0a0000, -44454255, -473a2053, -4646505f, -54595045, -5f313030, -30424153, -455f542e, -0a000000, -44454255, -473a2049, -32432065, -72726f72, -20696e20, -53465050, -5f545950, -452e0a00, -44454255, -473a2054, -77696e41, -782e0a00, -44454255, -473a2055, -6e6b6e6f, -776e2053, -46502b20, -74797065, -2e0a0000, 44657669, 63653a20, 00000000, @@ -4316,6 +4090,217 @@ ff95a23f, 2076616c, 75653a20, 00000000, +44454255, +473a2065, +74682531, +64205258, +4c4f5320, +6368616e, +67656420, +73746174, +653a2025, +640a0000, +44454255, +473a2065, +74682531, +64205458, +4641554c, +54206368, +616e6765, +64207374, +6174653a, +2025640a, +00000000, +44454255, +473a2065, +74682531, +64204d4f, +44414253, +20636861, +6e676564, +20737461, +74653a20, +25640a00, +494e464f, +3a20416e, +20534650, +2b206d6f, +64756c65, +20686173, +20626565, +6e207265, +6d6f7665, +64206672, +6f6d2065, +74682070, +6f727420, +25642e0a, +00000000, +494e464f, +3a204120, +6e657720, +5346502b, +206d6f64, +756c6520, +68617320, +6265656e, +20696e73, +65727465, +6420696e, +746f2065, +74682070, +6f727420, +25642e0a, +00000000, +44454255, +473a2053, +4646505f, +54595045, +5f53522e, +0a000000, +44454255, +473a2053, +4646505f, +54595045, +5f4c522e, +0a000000, +44454255, +473a2053, +4646505f, +54595045, +5f4c524d, +2e0a0000, +44454255, +473a2053, +4646505f, +54595045, +5f313030, +30424153, +455f5358, +2e0a0000, +44454255, +473a2053, +4646505f, +54595045, +5f313030, +30424153, +455f4c58, +2e0a0000, +44454255, +473a2053, +4646505f, +54595045, +5f313030, +30424153, +455f542e, +0a000000, +44454255, +473a2049, +32432065, +72726f72, +20696e20, +53465050, +5f545950, +452e0a00, +44454255, +473a2054, +77696e41, +782e0a00, +44454255, +473a2055, +6e6b6e6f, +776e2053, +46502b20, +74797065, +2e0a0000, +000023cf, +000023d6, +000023c9, +000023c9, +000023c9, +000023c9, +000023d6, +000023d6, +000023d6, +000023d6, +000023d6, +000023c3, +000023d6, +000023d6, +000023bd, +000023b7, +00002512, +0000250c, +00002506, +00002500, +000024fa, +000024f4, +000024ee, +000024e8, +00002619, +0000282e, +0000282e, +0000282e, +00002612, +0000260b, +00002604, +000025fd, +000025f6, +000025ef, +000025e8, +000025e1, +000025da, +000025d3, +000025cc, +000025c5, +00002764, +00002756, +00002748, +0000273a, +0000272b, +0000271b, +0000270b, +000026fb, +000026eb, +000026db, +000026d4, +000026cd, +000026bd, +000026ad, +00002773, +00002696, +000027d2, +000027cc, +000027c6, +000027c0, +00002825, +00002825, +00002825, +00002825, +00002825, +00002825, +00002825, +000027ba, +000027b4, +00000000, +00000001, +00000004, +00000005, +00000006, +00000007, +00000008, +00000020, +00000021, +00000000, +00000001, +00000004, +00000005, +00000006, +00000007, +00000008, +0000000a, +0000000b, +0000ffff, 30313233, 34353637, 38394142, @@ -4334,7 +4319,7 @@ ffffff00, 00000000, 00000000, 00000000, -0000479c, +00004760, 00000000, 00000000, 0050c285, @@ -4355,12 +4340,12 @@ c0a82802, 00000000, 00000000, 00006000, -0000438c, -00004414, +00004350, +000043d8, 00000000, -0000467c, -000046d8, -00004734, +00004640, +0000469c, +000046f8, 00000000, 00000000, 00000000, @@ -4370,7 +4355,7 @@ c0a82802, 00000000, 00000000, 00000000, -00004398, +0000435c, 00000000, 00000000, 00000000, @@ -8191,4 +8176,19 @@ ffffffff, 00000000, 00000000, 00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, +00000000, 00000000;
\ No newline at end of file diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 4ecdbd506..28ad6b968 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -154,15 +154,11 @@ IF(MSVC) ENDIF(MSVC) SET(Boost_ADDITIONAL_VERSIONS - "1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39" - "1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44" - "1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49" - "1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54" - "1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59" - "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64" - "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" + "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44" "1.45.0" "1.45" + "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.48.0" "1.49" "1.50.0" "1.50" + "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54" "1.55.0" "1.55" ) -FIND_PACKAGE(Boost 1.36 COMPONENTS ${BOOST_REQUIRED_COMPONENTS}) +FIND_PACKAGE(Boost 1.41 COMPONENTS ${BOOST_REQUIRED_COMPONENTS}) INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) diff --git a/host/docs/usrp_x3x0_config.rst b/host/docs/usrp_x3x0_config.rst index 9cb000275..22ef8c595 100644 --- a/host/docs/usrp_x3x0_config.rst +++ b/host/docs/usrp_x3x0_config.rst @@ -69,19 +69,20 @@ Configuring the MTU ------------------------------------- In order to achieve maximum performance, we recommend setting the MTU size to 9000 for 10 GigE and 1500 for 1 GigE. It is possible to use smaller MTUs, but this -can affect performance. With some NICs, setting the MTU too high can also cause issues, -though. To set the MTU to 9000, you can use the following command: +can affect performance. With some NICs, setting the MTU too high can also cause issues. +To set the MTU to 9000, you can use the following command: :: sudo ifconfig <interface> mtu 9000 # For 10 GigE + sudo ifconfig <interface> mtu 1500 # For 1 GigE Using these MTUs will set the frame sizes for UHD communication to 8000 and 1472, respectively. In some cases, specifying the frame size manually by adding the argument "<send/recv>_frame_size=1472" can solve issues. Note that a frame size of 1472 will limit -the available sampling rate, although this is likely not a problem issue on 1 GigE. +the available sampling rate, although this is not a problem on 1 GigE. Configuring the Firewall diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 8fb5115c2..de4721be0 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -56,6 +56,8 @@ public: * * \param addr a string representing the destination address * \param port a string representing the destination port + * \param default_buff_args Default values for frame sizes and num frames + * \param[out] buff_params_out Returns the actual buffer sizes * \param hints optional parameters to pass to the underlying transport */ static sptr make( diff --git a/host/lib/transport/nirio/rpc/rpc_client.cpp b/host/lib/transport/nirio/rpc/rpc_client.cpp index a5f8cf412..f8dc26b50 100644 --- a/host/lib/transport/nirio/rpc/rpc_client.cpp +++ b/host/lib/transport/nirio/rpc/rpc_client.cpp @@ -17,7 +17,9 @@ #include <uhd/transport/nirio/rpc/rpc_client.hpp> #include <boost/bind.hpp> +#include <boost/version.hpp> #include <boost/format.hpp> +#include <boost/asio/error.hpp> #define CHAIN_BLOCKING_XFER(func, exp, status) \ if (status) { \ @@ -48,7 +50,23 @@ rpc_client::rpc_client ( tcp::resolver resolver(_io_service); tcp::resolver::query query(tcp::v4(), server, port); tcp::resolver::iterator iterator = resolver.resolve(query); - boost::asio::connect(_socket, iterator); + + #if BOOST_VERSION < 104700 + // default constructor creates end iterator + tcp::resolver::iterator end; + + boost::system::error_code error = boost::asio::error::host_not_found; + while (error && iterator != end) + { + _socket.close(); + _socket.connect(*iterator++, error); + } + if (error) + throw boost::system::system_error(error); + #else + boost::asio::connect(_socket, iterator); + #endif + UHD_LOG << "rpc_client connected to server." << std::endl; try { @@ -74,18 +92,18 @@ rpc_client::rpc_client ( _io_service_thread.reset(new boost::thread(boost::bind(&boost::asio::io_service::run, &_io_service))); } else { UHD_LOG << "rpc_client handshake failed." << std::endl; - _exec_err.assign(boost::asio::error::connection_refused, boost::system::system_category()); + _exec_err.assign(boost::asio::error::connection_refused, boost::asio::error::get_system_category()); } UHD_LOG << boost::format("rpc_client archive = %d, rpc_server archive = %d\n.") % _hshake_args_client.boost_archive_version % _hshake_args_server.boost_archive_version; } catch (boost::exception&) { UHD_LOG << "rpc_client handshake aborted." << std::endl; - _exec_err.assign(boost::asio::error::connection_refused, boost::system::system_category()); + _exec_err.assign(boost::asio::error::connection_refused, boost::asio::error::get_system_category()); } } catch (boost::exception&) { UHD_LOG << "rpc_client connection request cancelled/aborted." << std::endl; - _exec_err.assign(boost::asio::error::connection_aborted, boost::system::system_category()); + _exec_err.assign(boost::asio::error::connection_aborted, boost::asio::error::get_system_category()); } } @@ -115,9 +133,12 @@ const boost::system::error_code& rpc_client::call( CHAIN_BLOCKING_XFER( boost::asio::write(_socket, boost::asio::buffer(&_request.header, sizeof(_request.header))), sizeof(_request.header), status); - CHAIN_BLOCKING_XFER( - boost::asio::write(_socket, boost::asio::buffer(&(*_request.data.begin()), _request.data.size())), - _request.data.size(), status); + if (not _request.data.empty()) + { + CHAIN_BLOCKING_XFER( + boost::asio::write(_socket, boost::asio::buffer(&(*_request.data.begin()), _request.data.size())), + _request.data.size(), status); + } } catch (boost::exception&) { status = false; } @@ -126,18 +147,18 @@ const boost::system::error_code& rpc_client::call( if (status) { if (!_exec_gate.timed_wait(lock, timeout)) { UHD_LOG << "rpc_client function timed out." << std::endl; - _exec_err.assign(boost::asio::error::timed_out, boost::system::system_category()); + _exec_err.assign(boost::asio::error::timed_out, boost::asio::error::get_system_category()); } } else { UHD_LOG << "rpc_client connection dropped." << std::endl; - _exec_err.assign(boost::asio::error::connection_aborted, boost::system::system_category()); + _exec_err.assign(boost::asio::error::connection_aborted, boost::asio::error::get_system_category()); _stop_io_service(); } //Verify that we are talking to the correct endpoint if ((_request.header.client_id != _response.header.client_id) && !_exec_err) { UHD_LOG << "rpc_client confused about who its talking to." << std::endl; - _exec_err.assign(boost::asio::error::operation_aborted, boost::system::system_category()); + _exec_err.assign(boost::asio::error::operation_aborted, boost::asio::error::get_system_category()); } if (!_exec_err) out_args.load(_response.data); @@ -153,19 +174,24 @@ void rpc_client::_handle_response_hdr(const boost::system::error_code& err, size if (!_exec_err && (transferred == expected)) { //Response header received. Verify that it is expected if (func_args_header_t::match_function(_request.header, _response.header)) { - _response.data.resize(_response.header.func_args_size); - - //Wait for response data - boost::asio::async_read(_socket, - boost::asio::buffer(&(*_response.data.begin()), _response.data.size()), - boost::bind(&rpc_client::_handle_response_data, this, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred, - _response.data.size())); + if (_response.header.func_args_size) + { + _response.data.resize(_response.header.func_args_size); + + //Wait for response data + boost::asio::async_read(_socket, + boost::asio::buffer(&(*_response.data.begin()), _response.data.size()), + boost::bind(&rpc_client::_handle_response_data, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + _response.data.size())); + } else { + _handle_response_data(err, 0, 0); + } } else { //Unexpected response. Ignore it. UHD_LOG << "rpc_client received garbage responses." << std::endl; - _exec_err.assign(boost::asio::error::operation_aborted, boost::system::system_category()); + _exec_err.assign(boost::asio::error::operation_aborted, boost::asio::error::get_system_category()); _wait_for_next_response_header(); } @@ -179,7 +205,7 @@ void rpc_client::_handle_response_data(const boost::system::error_code& err, siz boost::mutex::scoped_lock lock(_mutex); _exec_err = err; if (transferred != expected) { - _exec_err.assign(boost::asio::error::operation_aborted, boost::system::system_category()); + _exec_err.assign(boost::asio::error::operation_aborted, boost::asio::error::get_system_category()); } _exec_gate.notify_all(); diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 5fdf2594d..5c84327a4 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -154,28 +154,12 @@ public: /*! * Flush all transports in the streamer: - * This calls into get_and_process_single_packet(), - * so the sequence and flow control are handled. - * However, the packet payload is discarded. + * The packet payload is discarded. */ void flush_all(const double timeout = 0.0) { - increment_buffer_info(); //increment to next buffer - - for (size_t i = 0; i < _props.size(); i++) - { - while (true) //while (_props.at(i).get_buff(timeout)); - { - //receive a single packet from the transport - try - { - if (get_and_process_single_packet(i, - get_prev_buffer_info(), - get_curr_buffer_info(), - timeout) == PACKET_TIMEOUT_ERROR) break; - }catch(...){} - } - } + _flush_all(timeout); + return; } /*! @@ -379,12 +363,12 @@ private: ******************************************************************/ UHD_INLINE packet_type get_and_process_single_packet( const size_t index, - buffers_info_type &prev_buffer_info, - buffers_info_type &curr_buffer_info, + per_buffer_info_type &prev_buffer_info, + per_buffer_info_type &curr_buffer_info, double timeout ){ //get a single packet from the transport layer - managed_recv_buffer::sptr &buff = curr_buffer_info[index].buff; + managed_recv_buffer::sptr &buff = curr_buffer_info.buff; buff = _props[index].get_buff(timeout); if (buff.get() == NULL) return PACKET_TIMEOUT_ERROR; @@ -405,7 +389,7 @@ private: } //extract packet info - per_buffer_info_type &info = curr_buffer_info[index]; + per_buffer_info_type &info = curr_buffer_info; info.ifpi.num_packet_words32 = num_packet_words32 - _header_offset_words32; info.vrt_hdr = buff->cast<const boost::uint32_t *>() + _header_offset_words32; _vrt_unpacker(info.vrt_hdr, info.ifpi); @@ -442,7 +426,7 @@ private: #endif //3) check for out of order timestamps - if (info.ifpi.has_tsf and prev_buffer_info[index].time > info.time){ + if (info.ifpi.has_tsf and prev_buffer_info.time > info.time){ return PACKET_TIMESTAMP_ERROR; } @@ -450,6 +434,33 @@ private: return PACKET_IF_DATA; } + void _flush_all(double timeout) + { + for (size_t i = 0; i < _props.size(); i++) + { + per_buffer_info_type prev_buffer_info, curr_buffer_info; + while (true) + { + //receive a single packet from the transport + try + { + // call into get_and_process_single_packet() + // to make sure flow control is handled + if (get_and_process_single_packet( + i, + prev_buffer_info, + curr_buffer_info, + timeout) == PACKET_TIMEOUT_ERROR) break; + } catch(...){} + prev_buffer_info = curr_buffer_info; + curr_buffer_info.reset(); + } + } + get_prev_buffer_info().reset(); + get_curr_buffer_info().reset(); + get_next_buffer_info().reset(); + } + /******************************************************************* * Alignment check: * Check the received packet for alignment and mark accordingly. @@ -509,7 +520,7 @@ private: //receive a single packet from the transport try{ packet = get_and_process_single_packet( - index, prev_info, curr_info, timeout + index, prev_info[index], curr_info[index], timeout ); } @@ -545,7 +556,9 @@ private: curr_info.metadata.time_spec = next_info[index].time; curr_info.metadata.error_code = rx_metadata_t::error_code_t(get_context_code(next_info[index].vrt_hdr, next_info[index].ifpi)); if (curr_info.metadata.error_code == rx_metadata_t::ERROR_CODE_OVERFLOW){ + rx_metadata_t metadata = curr_info.metadata; _props[index].handle_overflow(); + curr_info.metadata = metadata; UHD_MSG(fastpath) << "O"; } return; diff --git a/host/lib/transport/udp_wsa_zero_copy.cpp b/host/lib/transport/udp_wsa_zero_copy.cpp index 031d26374..52382f84d 100644 --- a/host/lib/transport/udp_wsa_zero_copy.cpp +++ b/host/lib/transport/udp_wsa_zero_copy.cpp @@ -276,6 +276,36 @@ public: size_t get_num_send_frames(void) const {return _num_send_frames;} size_t get_send_frame_size(void) const {return _send_frame_size;} + //! Read back the socket's buffer space reserved for receives + size_t get_recv_buff_size(void) { + int recv_buff_size = 0; + int opt_len = sizeof(recv_buff_size); + getsockopt( + _sock_fd, + SOL_SOCKET, + SO_RCVBUF, + (char *)&recv_buff_size, + (int *)&opt_len + ); + + return (size_t) recv_buff_size; + } + + //! Read back the socket's buffer space reserved for sends + size_t get_send_buff_size(void) { + int send_buff_size = 0; + int opt_len = sizeof(send_buff_size); + getsockopt( + _sock_fd, + SOL_SOCKET, + SO_SNDBUF, + (char *)&send_buff_size, + (int *)&opt_len + ); + + return (size_t) send_buff_size; + } + private: //memory management -> buffers and fifos const size_t _recv_frame_size, _num_recv_frames; @@ -292,6 +322,25 @@ private: /*********************************************************************** * UDP zero copy make function **********************************************************************/ +void check_usr_buff_size( + size_t actual_buff_size, + size_t user_buff_size, // Set this to zero for no user-defined preference + const std::string tx_rx +){ + UHD_LOG << boost::format( + "Target %s sock buff size: %d bytes\n" + "Actual %s sock buff size: %d bytes" + ) % tx_rx % user_buff_size % tx_rx % actual_buff_size << std::endl; + if ((user_buff_size != 0.0) and (actual_buff_size < user_buff_size)) UHD_MSG(warning) << boost::format( + "The %s buffer could not be resized sufficiently.\n" + "Target sock buff size: %d bytes.\n" + "Actual sock buff size: %d bytes.\n" + "See the transport application notes on buffer resizing.\n" + ) % tx_rx % user_buff_size % actual_buff_size; +} + + + udp_zero_copy::sptr udp_zero_copy::make( const std::string &addr, const std::string &port, @@ -306,6 +355,34 @@ udp_zero_copy::sptr udp_zero_copy::make( xport_params.num_recv_frames = size_t(hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); xport_params.send_frame_size = size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); xport_params.num_send_frames = size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); - - return sptr(new udp_zero_copy_wsa_impl(addr, port, xport_params, hints)); + + //extract buffer size hints from the device addr and check if they match up + size_t usr_recv_buff_size = size_t(hints.cast<double>("recv_buff_size", 0.0)); + size_t usr_send_buff_size = size_t(hints.cast<double>("send_buff_size", 0.0)); + if (hints.has_key("recv_buff_size")) { + if (usr_recv_buff_size < xport_params.recv_frame_size * xport_params.num_recv_frames) { + throw uhd::value_error((boost::format( + "recv_buff_size must be equal to or greater than (num_recv_frames * recv_frame_size) where num_recv_frames=%d, recv_frame_size=%d") + % xport_params.num_recv_frames % xport_params.recv_frame_size).str()); + } + } + if (hints.has_key("send_buff_size")) { + if (usr_send_buff_size < xport_params.send_frame_size * xport_params.num_send_frames) { + throw uhd::value_error((boost::format( + "send_buff_size must be equal to or greater than (num_send_frames * send_frame_size) where num_send_frames=%d, send_frame_size=%d") + % xport_params.num_send_frames % xport_params.send_frame_size).str()); + } + } + + udp_zero_copy_wsa_impl::sptr udp_trans( + new udp_zero_copy_wsa_impl(addr, port, xport_params, hints) + ); + + // Read back the actual socket buffer sizes + buff_params_out.recv_buff_size = udp_trans->get_recv_buff_size(); + buff_params_out.send_buff_size = udp_trans->get_send_buff_size(); + check_usr_buff_size(buff_params_out.recv_buff_size, usr_recv_buff_size, "recv"); + check_usr_buff_size(buff_params_out.send_buff_size, usr_send_buff_size, "send"); + + return udp_trans; } diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 74e61143b..66df1f3bc 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2012-2013 Ettus Research LLC +// Copyright 2012-2014 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -373,12 +373,15 @@ b200_impl::b200_impl(const device_addr_t &device_addr) //////////////////////////////////////////////////////////////////// // create frontend mapping //////////////////////////////////////////////////////////////////// + std::vector<size_t> default_map(2, 0); default_map[1] = 1; // Set this to A->0 B->1 even if there's only A + _tree->create<std::vector<size_t> >(mb_path / "rx_chan_dsp_mapping").set(default_map); + _tree->create<std::vector<size_t> >(mb_path / "tx_chan_dsp_mapping").set(default_map); _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") .set(subdev_spec_t()) - .subscribe(boost::bind(&b200_impl::update_rx_subdev_spec, this, _1)); + .subscribe(boost::bind(&b200_impl::update_subdev_spec, this, "rx", _1)); _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") .set(subdev_spec_t()) - .subscribe(boost::bind(&b200_impl::update_tx_subdev_spec, this, _1)); + .subscribe(boost::bind(&b200_impl::update_subdev_spec, this, "tx", _1)); //////////////////////////////////////////////////////////////////// // setup radio control diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index c88d14ad5..a370e54f9 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -127,8 +127,7 @@ private: void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &); void check_fw_compat(void); void check_fpga_compat(void); - void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &); - void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_subdev_spec(const std::string &tx_rx, const uhd::usrp::subdev_spec_t &); void update_time_source(const std::string &); void update_clock_source(const std::string &); void update_bandsel(const std::string& which, double freq); @@ -150,8 +149,12 @@ private: bool ant_rx2; }; std::vector<radio_perifs_t> _radio_perifs; - void setup_radio(const size_t which_radio); - void handle_overflow(const size_t index); + + /*! \brief Setup the DSP chain for one radio front-end. + * + */ + void setup_radio(const size_t radio_index); + void handle_overflow(const size_t radio_index); struct gpio_state { boost::uint32_t tx_bandsel_a, tx_bandsel_b, rx_bandsel_a, rx_bandsel_b, rx_bandsel_c, codec_arst, mimo, ref_sel; diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 4768aa37b..4f072c4d4 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -72,44 +72,31 @@ void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate) /*********************************************************************** * frontend selection **********************************************************************/ -void b200_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) +void b200_impl::update_subdev_spec(const std::string &tx_rx, const uhd::usrp::subdev_spec_t &spec) { //sanity checking - if (spec.size()) validate_subdev_spec(_tree, spec, "rx"); + if (spec.size()) validate_subdev_spec(_tree, spec, tx_rx); UHD_ASSERT_THROW(spec.size() <= _radio_perifs.size()); - if (spec.size() > 0) + if (spec.size() >= 1) { UHD_ASSERT_THROW(spec[0].db_name == "A"); - UHD_ASSERT_THROW(spec[0].sd_name == "A"); + UHD_ASSERT_THROW(spec[0].sd_name == "A" or spec[0].sd_name == "B"); } - if (spec.size() > 1) + if (spec.size() == 2) { - //TODO we can support swapping at a later date, only this combo is supported UHD_ASSERT_THROW(spec[1].db_name == "A"); - UHD_ASSERT_THROW(spec[1].sd_name == "B"); + UHD_ASSERT_THROW( + (spec[0].sd_name == "A" and spec[1].sd_name == "B") or + (spec[0].sd_name == "B" and spec[1].sd_name == "A") + ); } - this->update_enables(); -} - -void b200_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) -{ - //sanity checking - if (spec.size()) validate_subdev_spec(_tree, spec, "tx"); - UHD_ASSERT_THROW(spec.size() <= _radio_perifs.size()); - - if (spec.size() > 0) - { - UHD_ASSERT_THROW(spec[0].db_name == "A"); - UHD_ASSERT_THROW(spec[0].sd_name == "A"); - } - if (spec.size() > 1) - { - //TODO we can support swapping at a later date, only this combo is supported - UHD_ASSERT_THROW(spec[1].db_name == "A"); - UHD_ASSERT_THROW(spec[1].sd_name == "B"); + std::vector<size_t> chan_to_dsp_map(spec.size(), 0); + for (size_t i = 0; i < spec.size(); i++) { + chan_to_dsp_map[i] = (spec[i].sd_name == "A") ? 0 : 1; } + _tree->access<std::vector<size_t> >("/mboards/0" / (tx_rx + "_chan_dsp_mapping")).set(chan_to_dsp_map); this->update_enables(); } @@ -238,13 +225,14 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_) boost::shared_ptr<sph::recv_packet_streamer> my_streamer; for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) { - const size_t chan = args.channels[stream_i]; - radio_perifs_t &perif = _radio_perifs[chan]; + const size_t radio_index = _tree->access<std::vector<size_t> >("/mboards/0/rx_chan_dsp_mapping") + .get().at(args.channels[stream_i]); + radio_perifs_t &perif = _radio_perifs[radio_index]; if (args.otw_format == "sc16") perif.ctrl->poke32(TOREG(SR_RX_FMT), 0); if (args.otw_format == "sc12") perif.ctrl->poke32(TOREG(SR_RX_FMT), 1); if (args.otw_format == "fc32") perif.ctrl->poke32(TOREG(SR_RX_FMT), 2); if (args.otw_format == "sc8") perif.ctrl->poke32(TOREG(SR_RX_FMT), 3); - const boost::uint32_t sid = chan?B200_RX_DATA1_SID:B200_RX_DATA0_SID; + const boost::uint32_t sid = radio_index ? B200_RX_DATA1_SID : B200_RX_DATA0_SID; //calculate packet size static const size_t hdr_size = 0 @@ -283,7 +271,7 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_) &recv_packet_demuxer_3000::get_recv_buff, _demux, sid, _1 ), true /*flush*/); my_streamer->set_overflow_handler(stream_i, boost::bind( - &b200_impl::handle_overflow, this, chan + &b200_impl::handle_overflow, this, radio_index )); my_streamer->set_issue_stream_cmd(stream_i, boost::bind( &rx_vita_core_3000::issue_stream_command, perif.framer, _1 @@ -292,21 +280,21 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_) //sets all tick and samp rates on this streamer this->update_tick_rate(this->get_tick_rate()); - _tree->access<double>(str(boost::format("/mboards/0/rx_dsps/%u/rate/value") % chan)).update(); + _tree->access<double>(str(boost::format("/mboards/0/rx_dsps/%u/rate/value") % radio_index)).update(); } this->update_enables(); return my_streamer; } -void b200_impl::handle_overflow(const size_t i) +void b200_impl::handle_overflow(const size_t radio_index) { boost::shared_ptr<sph::recv_packet_streamer> my_streamer = - boost::dynamic_pointer_cast<sph::recv_packet_streamer>(_radio_perifs[i].rx_streamer.lock()); + boost::dynamic_pointer_cast<sph::recv_packet_streamer>(_radio_perifs[radio_index].rx_streamer.lock()); if (my_streamer->get_num_channels() == 2) //MIMO time { //find out if we were in continuous mode before stopping - const bool in_continuous_streaming_mode = _radio_perifs[i].framer->in_continuous_streaming_mode(); + const bool in_continuous_streaming_mode = _radio_perifs[radio_index].framer->in_continuous_streaming_mode(); //stop streaming my_streamer->issue_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //flush demux @@ -319,11 +307,11 @@ void b200_impl::handle_overflow(const size_t i) { stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); stream_cmd.stream_now = false; - stream_cmd.time_spec = _radio_perifs[i].time64->get_time_now() + time_spec_t(0.01); + stream_cmd.time_spec = _radio_perifs[radio_index].time64->get_time_now() + time_spec_t(0.01); my_streamer->issue_stream_cmd(stream_cmd); } } - else _radio_perifs[i].framer->handle_overflow(); + else _radio_perifs[radio_index].framer->handle_overflow(); } /*********************************************************************** @@ -340,8 +328,9 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_) boost::shared_ptr<sph::send_packet_streamer> my_streamer; for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) { - const size_t chan = args.channels[stream_i]; - radio_perifs_t &perif = _radio_perifs[chan]; + const size_t radio_index = _tree->access<std::vector<size_t> >("/mboards/0/tx_chan_dsp_mapping") + .get().at(args.channels[stream_i]); + radio_perifs_t &perif = _radio_perifs[radio_index]; if (args.otw_format == "sc16") perif.ctrl->poke32(TOREG(SR_TX_FMT), 0); if (args.otw_format == "sc12") perif.ctrl->poke32(TOREG(SR_TX_FMT), 1); if (args.otw_format == "fc32") perif.ctrl->poke32(TOREG(SR_TX_FMT), 2); @@ -382,13 +371,13 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_) my_streamer->set_async_receiver(boost::bind( &async_md_type::pop_with_timed_wait, _async_task_data->async_md, _1, _2 )); - my_streamer->set_xport_chan_sid(stream_i, true, chan?B200_TX_DATA1_SID:B200_TX_DATA0_SID); + my_streamer->set_xport_chan_sid(stream_i, true, radio_index ? B200_TX_DATA1_SID : B200_TX_DATA0_SID); my_streamer->set_enable_trailer(false); //TODO not implemented trailer support yet perif.tx_streamer = my_streamer; //store weak pointer //sets all tick and samp rates on this streamer this->update_tick_rate(this->get_tick_rate()); - _tree->access<double>(str(boost::format("/mboards/0/tx_dsps/%u/rate/value") % chan)).update(); + _tree->access<double>(str(boost::format("/mboards/0/tx_dsps/%u/rate/value") % radio_index)).update(); } this->update_enables(); diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 182e774fc..f08709669 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -35,14 +35,20 @@ using namespace uhd::usrp; const std::string multi_usrp::ALL_GAINS = ""; -UHD_INLINE std::string string_vector_to_string(std::vector<std::string> values, std::string delimeter = std::string(" ")) +UHD_INLINE std::string string_vector_to_string(std::vector<std::string> values, std::string delimiter = std::string(" ")) { std::string out = ""; for (std::vector<std::string>::iterator iter = values.begin(); iter != values.end(); iter++) - out += delimeter + *iter; + { + out += (iter != values.begin() ? delimiter : "") + *iter; + } return out; } +#define THROW_GAIN_NAME_ERROR(name,chan,dir) throw uhd::exception::runtime_error( \ + (boost::format("%s: gain \"%s\" not found for channel %d.\nAvailable gains: %s\n") % \ + __FUNCTION__ % name % chan % string_vector_to_string(get_##dir##_gain_names(chan))).str()); + /*********************************************************************** * Helper methods **********************************************************************/ @@ -671,10 +677,7 @@ public: try { return rx_gain_group(chan)->set_value(gain, name); } catch (uhd::key_error &e) { - std::stringstream err; - err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" << - "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl; - throw uhd::exception::runtime_error(err.str()); + THROW_GAIN_NAME_ERROR(name,chan,rx); } } @@ -682,10 +685,7 @@ public: try { return rx_gain_group(chan)->get_value(name); } catch (uhd::key_error &e) { - std::stringstream err; - err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" << - "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl; - throw uhd::exception::runtime_error(err.str()); + THROW_GAIN_NAME_ERROR(name,chan,rx); } } @@ -693,10 +693,7 @@ public: try { return rx_gain_group(chan)->get_range(name); } catch (uhd::key_error &e) { - std::stringstream err; - err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" << - "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl; - throw uhd::exception::runtime_error(err.str()); + THROW_GAIN_NAME_ERROR(name,chan,rx); } } @@ -861,10 +858,7 @@ public: try { return tx_gain_group(chan)->set_value(gain, name); } catch (uhd::key_error &e) { - std::stringstream err; - err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" << - "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl; - throw uhd::exception::runtime_error(err.str()); + THROW_GAIN_NAME_ERROR(name,chan,tx); } } @@ -872,10 +866,7 @@ public: try { return tx_gain_group(chan)->get_value(name); } catch (uhd::key_error &e) { - std::stringstream err; - err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" << - "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl; - throw uhd::exception::runtime_error(err.str()); + THROW_GAIN_NAME_ERROR(name,chan,tx); } } @@ -883,10 +874,7 @@ public: try { return tx_gain_group(chan)->get_range(name); } catch (uhd::key_error &e) { - std::stringstream err; - err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" << - "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl; - throw uhd::exception::runtime_error(err.str()); + THROW_GAIN_NAME_ERROR(name,chan,tx); } } @@ -1073,6 +1061,12 @@ private: fs_path rx_dsp_root(const size_t chan) { mboard_chan_pair mcp = rx_chan_to_mcp(chan); + if (_tree->exists(mb_root(mcp.mboard) / "rx_chan_dsp_mapping")) { + std::vector<size_t> map = _tree->access<std::vector<size_t> >(mb_root(mcp.mboard) / "rx_chan_dsp_mapping").get(); + UHD_ASSERT_THROW(map.size() > mcp.chan); + mcp.chan = map[mcp.chan]; + } + try { const std::string name = _tree->list(mb_root(mcp.mboard) / "rx_dsps").at(mcp.chan); @@ -1087,6 +1081,11 @@ private: fs_path tx_dsp_root(const size_t chan) { mboard_chan_pair mcp = tx_chan_to_mcp(chan); + if (_tree->exists(mb_root(mcp.mboard) / "tx_chan_dsp_mapping")) { + std::vector<size_t> map = _tree->access<std::vector<size_t> >(mb_root(mcp.mboard) / "tx_chan_dsp_mapping").get(); + UHD_ASSERT_THROW(map.size() > mcp.chan); + mcp.chan = map[mcp.chan]; + } try { const std::string name = _tree->list(mb_root(mcp.mboard) / "tx_dsps").at(mcp.chan); diff --git a/host/lib/usrp/x300/x300_clock_ctrl.cpp b/host/lib/usrp/x300/x300_clock_ctrl.cpp index a986928a7..a8b30a0ab 100644 --- a/host/lib/usrp/x300/x300_clock_ctrl.cpp +++ b/host/lib/usrp/x300/x300_clock_ctrl.cpp @@ -48,6 +48,10 @@ x300_clock_ctrl_impl(uhd::spi_iface::sptr spiface, set_master_clock_rate(master_clock_rate); } +void reset_clocks() { + set_master_clock_rate(_master_clock_rate); +} + void sync_clocks(void) { //soft sync: //put the sync IO into output mode - FPGA must be input diff --git a/host/lib/usrp/x300/x300_clock_ctrl.hpp b/host/lib/usrp/x300/x300_clock_ctrl.hpp index 0e3caf900..e9904d25c 100644 --- a/host/lib/usrp/x300/x300_clock_ctrl.hpp +++ b/host/lib/usrp/x300/x300_clock_ctrl.hpp @@ -78,6 +78,12 @@ public: * \param true = on, false = off */ virtual void set_ref_out(const bool) = 0; + + /*! Reset the clocks. + * Should be called if the reference clock changes + * to reduce the time required to achieve a lock. + */ + virtual void reset_clocks(void) = 0; }; #endif /* INCLUDED_X300_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index c470e9bff..632391644 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -31,7 +31,7 @@ extern "C" { #define X300_FW_COMPAT_MAJOR 3 #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 3 +#define X300_FPGA_COMPAT_MAJOR 4 //shared memory sections - in between the stack and the program space #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index b20897fc6..e492b2238 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -430,16 +430,16 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) // Detect the frame size on the path to the USRP try { - max_frame_sizes = determine_max_frame_size(mb.addr, req_max_frame_size); + _max_frame_sizes = determine_max_frame_size(mb.addr, req_max_frame_size); } catch(std::exception &e) { UHD_MSG(error) << e.what() << std::endl; } if ((mb.recv_args.has_key("recv_frame_size")) - && (req_max_frame_size.recv_frame_size < max_frame_sizes.recv_frame_size)) { + && (req_max_frame_size.recv_frame_size < _max_frame_sizes.recv_frame_size)) { UHD_MSG(warning) << boost::format("You requested a receive frame size of (%lu) but your NIC's max frame size is (%lu).") - % req_max_frame_size.recv_frame_size << max_frame_sizes.recv_frame_size << std::endl + % req_max_frame_size.recv_frame_size << _max_frame_sizes.recv_frame_size << std::endl << boost::format("Please verify your NIC's MTU setting using '%s' or set the recv_frame_size argument appropriately.") % mtu_tool << std::endl << "UHD will use the auto-detected max frame size for this connection." @@ -447,10 +447,10 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) } if ((mb.recv_args.has_key("send_frame_size")) - && (req_max_frame_size.send_frame_size < max_frame_sizes.send_frame_size)) { + && (req_max_frame_size.send_frame_size < _max_frame_sizes.send_frame_size)) { UHD_MSG(warning) << boost::format("You requested a send frame size of (%lu) but your NIC's max frame size is (%lu).") - % req_max_frame_size.send_frame_size << max_frame_sizes.send_frame_size << std::endl + % req_max_frame_size.send_frame_size << _max_frame_sizes.send_frame_size << std::endl << boost::format("Please verify your NIC's MTU setting using '%s' or set the send_frame_size argument appropriately.") % mtu_tool << std::endl << "UHD will use the auto-detected max frame size for this connection." @@ -458,8 +458,6 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) } } - const std::vector<std::string> DB_NAMES = boost::assign::list_of("A")("B"); - //create basic communication UHD_MSG(status) << "Setup basic communication..." << std::endl; if (mb.xport_path == "nirio") { @@ -579,20 +577,10 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// UHD_MSG(status) << "Setup RF frontend clocking..." << std::endl; - // Init shadow and clock source; the device comes up with it's internal - // clock source before locking to something else (if requested). - mb.clock_control_regs__clock_source = 0; - mb.clock_control_regs__pps_select = 0; - mb.clock_control_regs__pps_out_enb = 0; - mb.clock_control_regs__tcxo_enb = 1; - mb.clock_control_regs__gpsdo_pwr = 1; - this->update_clock_source(mb, "internal"); - this->update_clock_control(mb); - - size_t hw_rev = 0; + mb.hw_rev = 0; if(mb_eeprom.has_key("revision") and not mb_eeprom["revision"].empty()) { try { - hw_rev = boost::lexical_cast<size_t>(mb_eeprom["revision"]); + mb.hw_rev = boost::lexical_cast<size_t>(mb_eeprom["revision"]); } catch(...) { UHD_MSG(warning) << "Revision in EEPROM is invalid! Please reprogram your EEPROM." << std::endl; } @@ -600,17 +588,38 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) UHD_MSG(warning) << "No revision detected MB EEPROM must be reprogrammed!" << std::endl; } - if(hw_rev == 0) { + if(mb.hw_rev == 0) { UHD_MSG(warning) << "Defaulting to X300 RevD Clock Settings. This will result in non-optimal lock times." << std::endl; - hw_rev = X300_REV("D"); + mb.hw_rev = X300_REV("D"); } + //Initialize clock control with internal references and GPSDO power on. + mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL; + mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL; + mb.clock_control_regs_pps_out_enb = 0; + mb.clock_control_regs_tcxo_enb = 1; + mb.clock_control_regs_gpsdo_pwr = 1; + this->update_clock_control(mb); + + //Create clock control mb.clock = x300_clock_ctrl::make(mb.zpu_spi, 1 /*slaveno*/, - hw_rev, + mb.hw_rev, dev_addr.cast<double>("master_clock_rate", X300_DEFAULT_TICK_RATE), dev_addr.cast<double>("system_ref_rate", X300_DEFAULT_SYSREF_RATE)); + //wait for reference clock to lock + if(mb.hw_rev > 4) + { + try { + //FIXME: Need to verify timeout value to make sure lock can be achieved in < 1.0 seconds + wait_for_ref_locked(mb.zpu_ctrl, 1.0); + } catch (uhd::runtime_error &e) { + //Silently fail for now, but fix after we have the correct timeout value + //UHD_MSG(warning) << "Clock failed to lock to internal source during initialization." << std::endl; + } + } + //////////////////////////////////////////////////////////////////// // create clock properties //////////////////////////////////////////////////////////////////// @@ -664,8 +673,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) // setup radios //////////////////////////////////////////////////////////////////// UHD_MSG(status) << "Initialize Radio control..." << std::endl; - this->setup_radio(mb_i, 0, DB_NAMES[0]); - this->setup_radio(mb_i, 1, DB_NAMES[1]); + this->setup_radio(mb_i, "A"); + this->setup_radio(mb_i, "B"); //////////////////////////////////////////////////////////////////// // front panel gpio @@ -732,10 +741,13 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// // create frontend mapping //////////////////////////////////////////////////////////////////// + std::vector<size_t> default_map(2, 0); default_map[1] = 1; + _tree->create<std::vector<size_t> >(mb_path / "rx_chan_dsp_mapping").set(default_map); + _tree->create<std::vector<size_t> >(mb_path / "tx_chan_dsp_mapping").set(default_map); _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") - .subscribe(boost::bind(&x300_impl::update_rx_subdev_spec, this, mb_i, _1)); + .subscribe(boost::bind(&x300_impl::update_subdev_spec, this, "rx", mb_i, _1)); _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") - .subscribe(boost::bind(&x300_impl::update_tx_subdev_spec, this, mb_i, _1)); + .subscribe(boost::bind(&x300_impl::update_subdev_spec, this, "tx", mb_i, _1)); //////////////////////////////////////////////////////////////////// // and do the misc mboard sensors @@ -767,30 +779,42 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(rx_fe_spec); _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_fe_spec); - //GPS installed: use external ref, time, and init time spec - if (mb.gps and mb.gps->gps_detected()) - { - UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl; - _tree->access<std::string>(mb_path / "time_source" / "value").set("gpsdo"); - _tree->access<std::string>(mb_path / "clock_source" / "value").set("gpsdo"); - UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl; - const time_t tp = time_t(mb.gps->get_sensor("gps_time").to_int()+1); - _tree->access<time_spec_t>(mb_path / "time" / "pps").set(time_spec_t(tp)); - } - else - { - _tree->access<std::string>(mb_path / "time_source" / "value").set("external"); + UHD_MSG(status) << "Initializing clock and PPS references..." << std::endl; + try { + //First, try external source _tree->access<std::string>(mb_path / "clock_source" / "value").set("external"); - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - if (this->get_ref_locked(mb.zpu_ctrl).to_bool()) - { - UHD_MSG(status) << "Setting references to external sources" << std::endl; - } - else + wait_for_ref_locked(mb.zpu_ctrl, 1.0); + _tree->access<std::string>(mb_path / "time_source" / "value").set("external"); + UHD_MSG(status) << "References initialized to external sources" << std::endl; + } catch (uhd::exception::runtime_error &e) { + //No external source detected - set to the GPSDO if installed + if (mb.gps and mb.gps->gps_detected()) { - UHD_MSG(status) << "Setting references to internal sources" << std::endl; - _tree->access<std::string>(mb_path / "time_source" / "value").set("internal"); + _tree->access<std::string>(mb_path / "clock_source" / "value").set("gpsdo"); + try { + wait_for_ref_locked(mb.zpu_ctrl, 1.0); + } catch (uhd::exception::runtime_error &e) { + UHD_MSG(warning) << "Clock reference failed to lock to GPSDO during device initialization. " << + "Check for the lock before operation or ignore this warning if using another clock source." << std::endl; + } + _tree->access<std::string>(mb_path / "time_source" / "value").set("gpsdo"); + UHD_MSG(status) << "References initialized to GPSDO sources" << std::endl; + UHD_MSG(status) << "Initializing time to the GPSDO time" << std::endl; + const time_t tp = time_t(mb.gps->get_sensor("gps_time").to_int()+1); + _tree->access<time_spec_t>(mb_path / "time" / "pps").set(time_spec_t(tp)); + //wait for time to be set (timeout after 1 second) + for (int i = 0; i < 10 && tp != (_tree->access<time_spec_t>(mb_path / "time" / "pps").get()).get_full_secs(); i++) + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } else { _tree->access<std::string>(mb_path / "clock_source" / "value").set("internal"); + try { + wait_for_ref_locked(mb.zpu_ctrl, 1.0); + } catch (uhd::exception::runtime_error &e) { + UHD_MSG(warning) << "Clock reference failed to lock to internal source during device initialization. " << + "Check for the lock before operation or ignore this warning if using another clock source." << std::endl; + } + _tree->access<std::string>(mb_path / "time_source" / "value").set("internal"); + UHD_MSG(status) << "References initialized to internal sources" << std::endl; } } } @@ -824,20 +848,21 @@ static void check_adc(wb_iface::sptr iface, const boost::uint32_t val) UHD_ASSERT_THROW(adc_rb == val); } -void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string &db_name) +void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name) { const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_i); + UHD_ASSERT_THROW(mb_i < _mb.size()); mboard_members_t &mb = _mb[mb_i]; - radio_perifs_t &perif = mb.radio_perifs[i]; - const size_t dspno = i; + const size_t radio_index = mb.get_radio_index(slot_name); + radio_perifs_t &perif = mb.radio_perifs[radio_index]; //////////////////////////////////////////////////////////////////// // radio control //////////////////////////////////////////////////////////////////// - uint8_t dest = (i == 0)? X300_XB_DST_R0 : X300_XB_DST_R1; + uint8_t dest = (radio_index == 0)? X300_XB_DST_R0 : X300_XB_DST_R1; boost::uint32_t ctrl_sid; both_xports_t xport = this->make_transport(mb_i, dest, X300_RADIO_DEST_PREFIX_CTRL, device_addr_t(), ctrl_sid); - perif.ctrl = radio_ctrl_core_3000::make(mb.if_pkt_is_big_endian, xport.recv, xport.send, ctrl_sid, db_name); + perif.ctrl = radio_ctrl_core_3000::make(mb.if_pkt_is_big_endian, xport.recv, xport.send, ctrl_sid, slot_name); perif.ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 2)); //reset adc + dac perif.ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 1) | (1 << 0)); //out of reset + dac enable @@ -883,20 +908,20 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string //////////////////////////////////////////////////////////////// // create codec control objects //////////////////////////////////////////////////////////////// - _tree->create<int>(mb_path / "rx_codecs" / db_name / "gains"); //phony property so this dir exists - _tree->create<int>(mb_path / "tx_codecs" / db_name / "gains"); //phony property so this dir exists - _tree->create<std::string>(mb_path / "rx_codecs" / db_name / "name").set("ads62p48"); - _tree->create<std::string>(mb_path / "tx_codecs" / db_name / "name").set("ad9146"); + _tree->create<int>(mb_path / "rx_codecs" / slot_name / "gains"); //phony property so this dir exists + _tree->create<int>(mb_path / "tx_codecs" / slot_name / "gains"); //phony property so this dir exists + _tree->create<std::string>(mb_path / "rx_codecs" / slot_name / "name").set("ads62p48"); + _tree->create<std::string>(mb_path / "tx_codecs" / slot_name / "name").set("ad9146"); - _tree->create<meta_range_t>(mb_path / "rx_codecs" / db_name / "gains" / "digital" / "range").set(meta_range_t(0, 6.0, 0.5)); - _tree->create<double>(mb_path / "rx_codecs" / db_name / "gains" / "digital" / "value") + _tree->create<meta_range_t>(mb_path / "rx_codecs" / slot_name / "gains" / "digital" / "range").set(meta_range_t(0, 6.0, 0.5)); + _tree->create<double>(mb_path / "rx_codecs" / slot_name / "gains" / "digital" / "value") .subscribe(boost::bind(&x300_adc_ctrl::set_gain, perif.adc, _1)).set(0); //////////////////////////////////////////////////////////////////// // front end corrections //////////////////////////////////////////////////////////////////// perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT)); - const fs_path rx_fe_path = mb_path / "rx_frontends" / db_name; + const fs_path rx_fe_path = mb_path / "rx_frontends" / slot_name; _tree->create<std::complex<double> >(rx_fe_path / "dc_offset" / "value") .coerce(boost::bind(&rx_frontend_core_200::set_dc_offset, perif.rx_fe, _1)) .set(std::complex<double>(0.0, 0.0)); @@ -908,7 +933,7 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string .set(std::complex<double>(0.0, 0.0)); perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT)); - const fs_path tx_fe_path = mb_path / "tx_frontends" / db_name; + const fs_path tx_fe_path = mb_path / "tx_frontends" / slot_name; _tree->create<std::complex<double> >(tx_fe_path / "dc_offset" / "value") .coerce(boost::bind(&tx_frontend_core_200::set_dc_offset, perif.tx_fe, _1)) .set(std::complex<double>(0.0, 0.0)); @@ -927,12 +952,12 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string _tree->access<double>(mb_path / "tick_rate") .subscribe(boost::bind(&rx_vita_core_3000::set_tick_rate, perif.framer, _1)) .subscribe(boost::bind(&rx_dsp_core_3000::set_tick_rate, perif.ddc, _1)); - const fs_path rx_dsp_path = mb_path / "rx_dsps" / str(boost::format("%u") % dspno); + const fs_path rx_dsp_path = mb_path / "rx_dsps" / str(boost::format("%u") % radio_index); _tree->create<meta_range_t>(rx_dsp_path / "rate" / "range") .publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc)); _tree->create<double>(rx_dsp_path / "rate" / "value") .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1)) - .subscribe(boost::bind(&x300_impl::update_rx_samp_rate, this, boost::ref(mb), dspno, _1)) + .subscribe(boost::bind(&x300_impl::update_rx_samp_rate, this, boost::ref(mb), radio_index, _1)) .set(1e6); _tree->create<double>(rx_dsp_path / "freq" / "value") .coerce(boost::bind(&rx_dsp_core_3000::set_freq, perif.ddc, _1)) @@ -951,12 +976,12 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string _tree->access<double>(mb_path / "tick_rate") .subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1)) .subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1)); - const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % dspno); + const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % radio_index); _tree->create<meta_range_t>(tx_dsp_path / "rate" / "range") .publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc)); _tree->create<double>(tx_dsp_path / "rate" / "value") .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1)) - .subscribe(boost::bind(&x300_impl::update_tx_samp_rate, this, boost::ref(mb), dspno, _1)) + .subscribe(boost::bind(&x300_impl::update_tx_samp_rate, this, boost::ref(mb), radio_index, _1)) .set(1e6); _tree->create<double>(tx_dsp_path / "freq" / "value") .coerce(boost::bind(&tx_dsp_core_3000::set_freq, perif.duc, _1)) @@ -975,14 +1000,15 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string //////////////////////////////////////////////////////////////////// // create RF frontend interfacing //////////////////////////////////////////////////////////////////// - const size_t j = (db_name == "B")? 0x2 : 0x0; - _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db_name / "rx_eeprom") + const fs_path db_path = (mb_path / "dboards" / slot_name); + const size_t j = (slot_name == "B")? 0x2 : 0x0; + _tree->create<dboard_eeprom_t>(db_path / "rx_eeprom") .set(mb.db_eeproms[X300_DB0_RX_EEPROM | j]) .subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_RX_EEPROM | j), _1)); - _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db_name / "tx_eeprom") + _tree->create<dboard_eeprom_t>(db_path / "tx_eeprom") .set(mb.db_eeproms[X300_DB0_TX_EEPROM | j]) .subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_TX_EEPROM | j), _1)); - _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db_name / "gdb_eeprom") + _tree->create<dboard_eeprom_t>(db_path / "gdb_eeprom") .set(mb.db_eeproms[X300_DB0_GDB_EEPROM | j]) .subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_GDB_EEPROM | j), _1)); @@ -994,33 +1020,33 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string db_config.tx_spi_slaveno = DB_TX_SEN; db_config.i2c = mb.zpu_i2c; db_config.clock = mb.clock; - db_config.which_rx_clk = (db_name == "A")? X300_CLOCK_WHICH_DB0_RX : X300_CLOCK_WHICH_DB1_RX; - db_config.which_tx_clk = (db_name == "A")? X300_CLOCK_WHICH_DB0_TX : X300_CLOCK_WHICH_DB1_TX; - db_config.dboard_slot = (db_name == "A")? 0 : 1; - _dboard_ifaces[db_name] = x300_make_dboard_iface(db_config); + db_config.which_rx_clk = (slot_name == "A")? X300_CLOCK_WHICH_DB0_RX : X300_CLOCK_WHICH_DB1_RX; + db_config.which_tx_clk = (slot_name == "A")? X300_CLOCK_WHICH_DB0_TX : X300_CLOCK_WHICH_DB1_TX; + db_config.dboard_slot = (slot_name == "A")? 0 : 1; + _dboard_ifaces[db_path] = x300_make_dboard_iface(db_config); //create a new dboard manager - _tree->create<dboard_iface::sptr>(mb_path / "dboards" / db_name / "iface").set(_dboard_ifaces[db_name]); - _dboard_managers[db_name] = dboard_manager::make( + _tree->create<dboard_iface::sptr>(db_path / "iface").set(_dboard_ifaces[db_path]); + _dboard_managers[db_path] = dboard_manager::make( mb.db_eeproms[X300_DB0_RX_EEPROM | j].id, mb.db_eeproms[X300_DB0_TX_EEPROM | j].id, mb.db_eeproms[X300_DB0_GDB_EEPROM | j].id, - _dboard_ifaces[db_name], - _tree->subtree(mb_path / "dboards" / db_name) + _dboard_ifaces[db_path], + _tree->subtree(db_path) ); //now that dboard is created -- register into rx antenna event - const std::string fe_name = _tree->list(mb_path / "dboards" / db_name / "rx_frontends").front(); - _tree->access<std::string>(mb_path / "dboards" / db_name / "rx_frontends" / fe_name / "antenna" / "value") - .subscribe(boost::bind(&x300_impl::update_atr_leds, this, mb.radio_perifs[i].leds, _1)); - this->update_atr_leds(mb.radio_perifs[i].leds, ""); //init anyway, even if never called + const std::string fe_name = _tree->list(db_path / "rx_frontends").front(); + _tree->access<std::string>(db_path / "rx_frontends" / fe_name / "antenna" / "value") + .subscribe(boost::bind(&x300_impl::update_atr_leds, this, mb.radio_perifs[radio_index].leds, _1)); + this->update_atr_leds(mb.radio_perifs[radio_index].leds, ""); //init anyway, even if never called //bind frontend corrections to the dboard freq props - const fs_path db_rx_fe_path = mb_path / "dboards" / db_name / "rx_frontends"; + const fs_path db_rx_fe_path = db_path / "rx_frontends"; BOOST_FOREACH(const std::string &name, _tree->list(db_rx_fe_path)) { _tree->access<double>(db_rx_fe_path / name / "freq" / "value") - .subscribe(boost::bind(&x300_impl::set_rx_fe_corrections, this, mb_path, db_name, _1)); + .subscribe(boost::bind(&x300_impl::set_rx_fe_corrections, this, mb_path, slot_name, _1)); } } @@ -1120,29 +1146,28 @@ x300_impl::both_xports_t x300_impl::make_transport( /* Print a warning if the system's max available frame size is less than the most optimal * frame size for this type of connection. */ - if (max_frame_sizes.send_frame_size < eth_data_rec_frame_size) { + if (_max_frame_sizes.send_frame_size < eth_data_rec_frame_size) { UHD_MSG(warning) << boost::format("For this connection, UHD recommends a send frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.") % eth_data_rec_frame_size - % max_frame_sizes.send_frame_size + % _max_frame_sizes.send_frame_size << std::endl << "This will negatively impact your maximum achievable sample rate." << std::endl; } - if (max_frame_sizes.recv_frame_size < eth_data_rec_frame_size) { + if (_max_frame_sizes.recv_frame_size < eth_data_rec_frame_size) { UHD_MSG(warning) << boost::format("For this connection, UHD recommends a receive frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.") % eth_data_rec_frame_size - % max_frame_sizes.recv_frame_size + % _max_frame_sizes.recv_frame_size << std::endl << "This will negatively impact your maximum achievable sample rate." << std::endl; } - // Account for headers - size_t system_max_send_frame_size = (size_t) max_frame_sizes.send_frame_size - 64; - size_t system_max_recv_frame_size = (size_t) max_frame_sizes.recv_frame_size - 64; + size_t system_max_send_frame_size = (size_t) _max_frame_sizes.send_frame_size; + size_t system_max_recv_frame_size = (size_t) _max_frame_sizes.recv_frame_size; // Make sure frame sizes do not exceed the max available value supported by UHD default_buff_args.send_frame_size = @@ -1165,7 +1190,7 @@ x300_impl::both_xports_t x300_impl::make_transport( ? X300_ETH_DATA_NUM_FRAMES : X300_ETH_MSG_NUM_FRAMES; - //make a new transport - fpga has no idea how to talk to use on this yet + //make a new transport - fpga has no idea how to talk to us on this yet udp_zero_copy::buff_params buff_params; xports.recv = udp_zero_copy::make(mb.addr, BOOST_STRINGIZE(X300_VITA_UDP_PORT), @@ -1289,60 +1314,112 @@ void x300_impl::register_loopback_self_test(wb_iface::sptr iface) void x300_impl::set_time_source_out(mboard_members_t &mb, const bool enb) { - mb.clock_control_regs__pps_out_enb = enb? 1 : 0; + mb.clock_control_regs_pps_out_enb = enb? 1 : 0; this->update_clock_control(mb); } void x300_impl::update_clock_control(mboard_members_t &mb) { - const size_t reg = mb.clock_control_regs__clock_source - | (mb.clock_control_regs__pps_select << 2) - | (mb.clock_control_regs__pps_out_enb << 3) - | (mb.clock_control_regs__tcxo_enb << 4) - | (mb.clock_control_regs__gpsdo_pwr << 5) + const size_t reg = mb.clock_control_regs_clock_source + | (mb.clock_control_regs_pps_select << 2) + | (mb.clock_control_regs_pps_out_enb << 4) + | (mb.clock_control_regs_tcxo_enb << 5) + | (mb.clock_control_regs_gpsdo_pwr << 6) ; mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_CLOCK_CTRL), reg); } void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &source) { - mb.clock_control_regs__clock_source = 0; + mb.clock_control_regs_clock_source = 0; + mb.clock_control_regs_tcxo_enb = 0; if (source == "internal") { - mb.clock_control_regs__clock_source = 0x2; - - mb.clock_control_regs__tcxo_enb = (source == "internal")? 1 : 0; + mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL; + mb.clock_control_regs_tcxo_enb = 1; } else if (source == "external") { - mb.clock_control_regs__clock_source = 0x0; + mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL; } else if (source == "gpsdo") { - mb.clock_control_regs__clock_source = 0x3; + mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO; } else { throw uhd::key_error("update_clock_source: unknown source: " + source); } this->update_clock_control(mb); + + //reset the clock control + //without this, the lock time is long and can be as much as 30 seconds + mb.clock->reset_clocks(); + + /* FIXME: implement when we know the correct timeouts + * //wait for lock + * double timeout = 1.0; + * try { + * if (mb.hw_rev > 4) + * wait_for_ref_locked(mb.zpu_ctrl, timeout); + * } catch (uhd::runtime_error &e) { + * //failed to lock on reference + * throw uhd::runtime_error((boost::format("Clock failed to lock to %s source.") % source).str()); + * } + */ } void x300_impl::update_time_source(mboard_members_t &mb, const std::string &source) { if (source == "internal") { - // no action needed + mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL; } else if (source == "external") { - mb.clock_control_regs__pps_select = (source == "external")? 1 : 0; + mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL; } else if (source == "gpsdo") { - // no action needed + mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO; } else { throw uhd::key_error("update_time_source: unknown source: " + source); } this->update_clock_control(mb); + + //check for valid pps + if (!is_pps_present(mb.zpu_ctrl)) + { + throw uhd::runtime_error((boost::format("The %d PPS was not detected. Please check the PPS source and try again.") % source).str()); + } +} + +void x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout) +{ + boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::milliseconds(timeout * 1000.0); + do + { + if (get_ref_locked(ctrl).to_bool()) + return; + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } while (boost::get_system_time() < timeout_time); + + //failed to lock on reference + throw uhd::runtime_error("The reference clock failed to lock."); } sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl) { - const bool lock = (ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & (1 << 2)) != 0; + uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)); + const bool lock = ((clk_status & ZPU_RB_CLK_STATUS_LMK_LOCK) != 0); return sensor_value_t("Ref", lock, "locked", "unlocked"); } +bool x300_impl::is_pps_present(wb_iface::sptr ctrl) +{ + // The ZPU_RB_CLK_STATUS_PPS_DETECT bit toggles with each rising edge of the PPS. + // We monitor it for up to 1.5 seconds looking for it to toggle. + uint32_t pps_detect = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & ZPU_RB_CLK_STATUS_PPS_DETECT; + for (int i = 0; i < 15; i++) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)); + if (pps_detect != (clk_status & ZPU_RB_CLK_STATUS_PPS_DETECT)) + return true; + } + return false; +} + void x300_impl::set_db_eeprom(i2c_iface::sptr i2c, const size_t addr, const uhd::usrp::dboard_eeprom_t &db_eeprom) { db_eeprom.store(*i2c, addr); diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 1fb3676a0..259ea253d 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -82,8 +82,8 @@ static const double X300_DEFAULT_SYSREF_RATE = 10e6; #define X300_XB_DST_E0 0 #define X300_XB_DST_E1 1 -#define X300_XB_DST_R0 2 -#define X300_XB_DST_R1 3 +#define X300_XB_DST_R0 2 // Radio 0 -> Slot A +#define X300_XB_DST_R1 3 // Radio 1 -> Slot B #define X300_XB_DST_CE0 4 #define X300_XB_DST_CE1 5 #define X300_XB_DST_CE2 5 @@ -191,12 +191,13 @@ private: i2c_core_100_wb32::sptr zpu_i2c; //perifs in each radio - radio_perifs_t radio_perifs[2]; + radio_perifs_t radio_perifs[2]; //!< This is hardcoded s.t. radio_perifs[0] points to slot A and [1] to B uhd::usrp::dboard_eeprom_t db_eeproms[8]; - - //per mboard frontend mapping - uhd::usrp::subdev_spec_t rx_fe_map; - uhd::usrp::subdev_spec_t tx_fe_map; + //! Return the index of a radio component, given a slot name. This means DSPs, radio_perifs + size_t get_radio_index(const std::string &slot_name) { + UHD_ASSERT_THROW(slot_name == "A" or slot_name == "B"); + return slot_name == "A" ? 0 : 1; + } //other perifs on mboard x300_clock_ctrl::sptr clock; @@ -204,14 +205,16 @@ private: gpio_core_200::sptr fp_gpio; //clock control register bits - int clock_control_regs__clock_source; - int clock_control_regs__pps_select; - int clock_control_regs__pps_out_enb; - int clock_control_regs__tcxo_enb; - int clock_control_regs__gpsdo_pwr; + int clock_control_regs_clock_source; + int clock_control_regs_pps_select; + int clock_control_regs_pps_out_enb; + int clock_control_regs_tcxo_enb; + int clock_control_regs_gpsdo_pwr; //which FPGA image is loaded std::string loaded_fpga_image; + + size_t hw_rev; }; std::vector<mboard_members_t> _mb; @@ -222,7 +225,20 @@ private: void register_loopback_self_test(uhd::wb_iface::sptr iface); - void setup_radio(const size_t, const size_t which_radio, const std::string &db_name); + /*! \brief Initialize the radio component on a given slot. + * + * Call this function once per slot (A and B) and motherboard to initialize all the radio components. + * This will: + * - Reset and init DACs and ADCs + * - Setup controls for DAC, ADC, SPI and LEDs + * - Self test ADC + * - Sync DACs (for MIMO) + * - Initialize the property tree for control objects etc. (gain, rate...) + * + * \param mb_i Motherboard index + * \param slot_name Slot name (A or B). + */ + void setup_radio(const size_t, const std::string &slot_name); size_t _sid_framer; struct sid_config_t @@ -253,7 +269,7 @@ private: size_t recv_frame_size; size_t send_frame_size; }; - frame_size_t max_frame_sizes; + frame_size_t _max_frame_sizes; /*! * Automatically determine the maximum frame size available by sending a UDP packet @@ -288,8 +304,15 @@ private: void set_rx_fe_corrections(const uhd::fs_path &mb_path, const std::string &fe_name, const double lo_freq); - void update_rx_subdev_spec(const size_t, const uhd::usrp::subdev_spec_t &spec); - void update_tx_subdev_spec(const size_t, const uhd::usrp::subdev_spec_t &spec); + /*! Update the IQ MUX settings for the radio peripheral according to given subdev spec. + * + * Also checks if the given subdev is valid for this device and updates the channel to DSP mapping. + * + * \param tx_rx "tx" or "rx", depending where you're setting the subdev spec + * \param mb_i Mainboard index number. + * \param spec Subdev spec + */ + void update_subdev_spec(const std::string &tx_rx, const size_t mb_i, const uhd::usrp::subdev_spec_t &spec); void set_tick_rate(mboard_members_t &, const double); void update_tick_rate(mboard_members_t &, const double); @@ -302,6 +325,8 @@ private: void update_time_source(mboard_members_t&, const std::string &); uhd::sensor_value_t get_ref_locked(uhd::wb_iface::sptr); + void wait_for_ref_locked(uhd::wb_iface::sptr, double timeout = 0.0); + bool is_pps_present(uhd::wb_iface::sptr); void set_db_eeprom(uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t &); void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &); diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index 00a31b8d6..85de34a54 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -77,76 +77,52 @@ void x300_impl::update_tx_samp_rate(mboard_members_t &mb, const size_t dspno, co /*********************************************************************** * Setup dboard muxing for IQ **********************************************************************/ -void x300_impl::update_rx_subdev_spec(const size_t mb_i, const subdev_spec_t &spec) +void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i, const subdev_spec_t &spec) { + UHD_ASSERT_THROW(tx_rx == "tx" or tx_rx == "rx"); + UHD_ASSERT_THROW(mb_i < _mb.size()); const std::string mb_name = boost::lexical_cast<std::string>(mb_i); - fs_path root = "/mboards/"+mb_name+"/dboards"; + fs_path mb_root = "/mboards/" + mb_name; //sanity checking - validate_subdev_spec(_tree, spec, "rx", mb_name); + validate_subdev_spec(_tree, spec, tx_rx, mb_name); UHD_ASSERT_THROW(spec.size() <= 2); - if (spec.size() > 0) UHD_ASSERT_THROW(spec[0].db_name == "A"); - if (spec.size() > 1) UHD_ASSERT_THROW(spec[1].db_name == "B"); - - //setup mux for this spec - for (size_t i = 0; i < 2; i++) - { - //extract db name - const std::string db_name = (i == 0)? "A" : "B"; - if (i < spec.size()) UHD_ASSERT_THROW(spec[i].db_name == db_name); - - //extract fe name - std::string fe_name; - if (i < spec.size()) fe_name = spec[i].sd_name; - else fe_name = _tree->list(root / db_name / "rx_frontends").front(); - - //extract connection - const std::string conn = _tree->access<std::string>(root / db_name / "rx_frontends" / fe_name / "connection").get(); - - //swap condition - const bool fe_swapped = (conn == "QI" or conn == "Q"); - _mb[mb_i].radio_perifs[i].ddc->set_mux(conn, fe_swapped); - //see usrp/io_impl.cpp if multiple DSPs share the frontend: - _mb[mb_i].radio_perifs[i].rx_fe->set_mux(fe_swapped); + if (spec.size() == 1) { + UHD_ASSERT_THROW(spec[0].db_name == "A" || spec[0].db_name == "B"); + } + else if (spec.size() == 2) { + UHD_ASSERT_THROW( + (spec[0].db_name == "A" && spec[1].db_name == "B") || + (spec[0].db_name == "B" && spec[1].db_name == "A") + ); } - _mb[mb_i].rx_fe_map = spec; -} - -void x300_impl::update_tx_subdev_spec(const size_t mb_i, const subdev_spec_t &spec) -{ - const std::string mb_name = boost::lexical_cast<std::string>(mb_i); - fs_path root = "/mboards/"+mb_name+"/dboards"; - - //sanity checking - validate_subdev_spec(_tree, spec, "tx", mb_name); - UHD_ASSERT_THROW(spec.size() <= 2); - if (spec.size() > 0) UHD_ASSERT_THROW(spec[0].db_name == "A"); - if (spec.size() > 1) UHD_ASSERT_THROW(spec[1].db_name == "B"); - - //set the mux for this spec - for (size_t i = 0; i < 2; i++) + std::vector<size_t> chan_to_dsp_map(spec.size(), 0); + // setup mux for this spec + for (size_t i = 0; i < spec.size(); i++) { - //extract db name - const std::string db_name = (i == 0)? "A" : "B"; - if (i < spec.size()) UHD_ASSERT_THROW(spec[i].db_name == db_name); - - //extract fe name - std::string fe_name; - if (i < spec.size()) fe_name = spec[i].sd_name; - else fe_name = _tree->list(root / db_name / "tx_frontends").front(); + const int radio_idx = _mb[mb_i].get_radio_index(spec[i].db_name); + chan_to_dsp_map[i] = radio_idx; //extract connection - const std::string conn = _tree->access<std::string>(root / db_name / "tx_frontends" / fe_name / "connection").get(); - - //swap condition - _mb[mb_i].radio_perifs[i].tx_fe->set_mux(conn); + const std::string conn = _tree->access<std::string>(mb_root / "dboards" / spec[i].db_name / (tx_rx + "_frontends") / spec[i].sd_name / "connection").get(); + if (tx_rx == "tx") { + //swap condition + _mb[mb_i].radio_perifs[radio_idx].tx_fe->set_mux(conn); + } else { + //swap condition + const bool fe_swapped = (conn == "QI" or conn == "Q"); + _mb[mb_i].radio_perifs[radio_idx].ddc->set_mux(conn, fe_swapped); + //see usrp/io_impl.cpp if multiple DSPs share the frontend: + _mb[mb_i].radio_perifs[radio_idx].rx_fe->set_mux(fe_swapped); + } } - _mb[mb_i].tx_fe_map = spec; + _tree->access<std::vector<size_t> >(mb_root / (tx_rx + "_chan_dsp_mapping")).set(chan_to_dsp_map); } + /*********************************************************************** * VITA stuff **********************************************************************/ @@ -375,16 +351,28 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_) boost::shared_ptr<sph::recv_packet_streamer> my_streamer; for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) { + // Find the mainboard and subdev that corresponds to channel args.channels[stream_i] const size_t chan = args.channels[stream_i]; - size_t mb_chan = chan, mb_index = 0; - BOOST_FOREACH(mboard_members_t &mb, _mb) - { - if (mb_chan < mb.rx_fe_map.size()) break; - else mb_chan -= mb.rx_fe_map.size(); - mb_index++; + size_t mb_chan = chan, mb_index; + for (mb_index = 0; mb_index < _mb.size(); mb_index++) { + const subdev_spec_t &curr_subdev_spec = + _tree->access<subdev_spec_t>("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "rx_subdev_spec").get(); + if (mb_chan < curr_subdev_spec.size()) { + break; + } else { + mb_chan -= curr_subdev_spec.size(); + } } + + // Find the DSP that corresponds to this mainboard and subdev + UHD_ASSERT_THROW(mb_index < _mb.size()); mboard_members_t &mb = _mb[mb_index]; - radio_perifs_t &perif = mb.radio_perifs[mb_chan]; + const std::vector<size_t> dsp_map = _tree->access<std::vector<size_t> >("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "rx_chan_dsp_mapping") + .get(); //.at(mb_chan); + UHD_ASSERT_THROW(mb_chan < dsp_map.size()); + const size_t radio_index = dsp_map[mb_chan]; + UHD_ASSERT_THROW(radio_index < 2); + radio_perifs_t &perif = mb.radio_perifs[radio_index]; //setup the dsp transport hints (default to a large recv buff) device_addr_t device_addr = mb.recv_args; @@ -405,7 +393,7 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_) } //allocate sid and create transport - uint8_t dest = (mb_chan == 0)? X300_XB_DST_R0 : X300_XB_DST_R1; + uint8_t dest = (radio_index == 0)? X300_XB_DST_R0 : X300_XB_DST_R1; boost::uint32_t data_sid; UHD_LOG << "creating rx stream " << device_addr.to_string() << std::endl; both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_RX, device_addr, data_sid); @@ -419,9 +407,9 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_) - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; - const size_t bpp = xport.recv->get_recv_frame_size() - hdr_size; - const size_t bpi = convert::get_bytes_per_item(args.otw_format); - const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); + const size_t bpp = xport.recv->get_recv_frame_size() - hdr_size; // bytes per packet + const size_t bpi = convert::get_bytes_per_item(args.otw_format); // bytes per item + const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); // samples per packet //make the new streamer given the samples per packet if (not my_streamer) my_streamer = boost::make_shared<sph::recv_packet_streamer>(spp); @@ -488,12 +476,12 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_) ); //Store a weak pointer to prevent a streamer->x300_impl->streamer circular dependency - mb.rx_streamers[mb_chan] = boost::weak_ptr<sph::recv_packet_streamer>(my_streamer); + mb.rx_streamers[radio_index] = boost::weak_ptr<sph::recv_packet_streamer>(my_streamer); //sets all tick and samp rates on this streamer const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_index); _tree->access<double>(mb_path / "tick_rate").update(); - _tree->access<double>(mb_path / "rx_dsps" / boost::lexical_cast<std::string>(mb_chan) / "rate" / "value").update(); + _tree->access<double>(mb_path / "rx_dsps" / boost::lexical_cast<std::string>(radio_index) / "rate" / "value").update(); } return my_streamer; @@ -552,22 +540,29 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_) boost::shared_ptr<sph::send_packet_streamer> my_streamer; for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) { + // Find the mainboard and subdev that corresponds to channel args.channels[stream_i] const size_t chan = args.channels[stream_i]; - size_t mb_chan = chan, mb_index = 0; - BOOST_FOREACH(mboard_members_t &mb, _mb) - { - if (mb_chan < mb.tx_fe_map.size()) break; - else mb_chan -= mb.tx_fe_map.size(); - mb_index++; + size_t mb_chan = chan, mb_index; + for (mb_index = 0; mb_index < _mb.size(); mb_index++) { + const subdev_spec_t &curr_subdev_spec = + _tree->access<subdev_spec_t>("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "tx_subdev_spec").get(); + if (mb_chan < curr_subdev_spec.size()) { + break; + } else { + mb_chan -= curr_subdev_spec.size(); + } } + // Find the DSP that corresponds to this mainboard and subdev mboard_members_t &mb = _mb[mb_index]; - radio_perifs_t &perif = mb.radio_perifs[mb_chan]; + const size_t radio_index = _tree->access<std::vector<size_t> >("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "tx_chan_dsp_mapping") + .get().at(mb_chan); + radio_perifs_t &perif = mb.radio_perifs[radio_index]; //setup the dsp transport hints (TODO) device_addr_t device_addr = mb.send_args; //allocate sid and create transport - uint8_t dest = (mb_chan == 0)? X300_XB_DST_R0 : X300_XB_DST_R1; + uint8_t dest = (radio_index == 0)? X300_XB_DST_R0 : X300_XB_DST_R1; boost::uint32_t data_sid; UHD_LOG << "creating tx stream " << device_addr.to_string() << std::endl; both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_TX, device_addr, data_sid); @@ -640,12 +635,12 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_) my_streamer->set_enable_trailer(false); //TODO not implemented trailer support yet //Store a weak pointer to prevent a streamer->x300_impl->streamer circular dependency - mb.tx_streamers[mb_chan] = boost::weak_ptr<sph::send_packet_streamer>(my_streamer); + mb.tx_streamers[radio_index] = boost::weak_ptr<sph::send_packet_streamer>(my_streamer); //sets all tick and samp rates on this streamer const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_index); _tree->access<double>(mb_path / "tick_rate").update(); - _tree->access<double>(mb_path / "tx_dsps" / boost::lexical_cast<std::string>(mb_chan) / "rate" / "value").update(); + _tree->access<double>(mb_path / "tx_dsps" / boost::lexical_cast<std::string>(radio_index) / "rate" / "value").update(); } return my_streamer; diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index e4ae76a38..fb1786deb 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -68,12 +68,26 @@ localparam ZPU_SR_SPI = 32; localparam ZPU_SR_ETHINT0 = 40; localparam ZPU_SR_ETHINT1 = 56; +//clock controls +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03 + localparam ZPU_RB_SPI = 2; localparam ZPU_RB_CLK_STATUS = 3; localparam ZPU_RB_COMPAT_NUM = 6; localparam ZPU_RB_ETH_TYPE0 = 4; localparam ZPU_RB_ETH_TYPE1 = 5; +//clock status +#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0) +#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2) +#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3) +#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4) + //spi slaves on radio #define DB_DAC_SEN (1 << 7) #define DB_ADC_SEN (1 << 6) diff --git a/host/utils/uhd_cal_rx_iq_balance.cpp b/host/utils/uhd_cal_rx_iq_balance.cpp index 5fb494114..551da7544 100644 --- a/host/utils/uhd_cal_rx_iq_balance.cpp +++ b/host/utils/uhd_cal_rx_iq_balance.cpp @@ -20,6 +20,7 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/utils/paths.hpp> #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/msg.hpp> #include <uhd/usrp/multi_usrp.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> @@ -93,7 +94,7 @@ static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double rx_l * Main **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ - std::string args; + std::string args, subdev, serial; double tx_wave_ampl, tx_offset; double freq_start, freq_stop, freq_step; size_t nsamps; @@ -102,7 +103,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ desc.add_options() ("help", "help message") ("verbose", "enable some verbose") - ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") + ("args", po::value<std::string>(&args)->default_value(""), "Device address args [default = \"\"]") + ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')") ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts") ("tx_offset", po::value<double>(&tx_offset)->default_value(.9344e6), "TX LO offset from the RX LO in Hz") ("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)") @@ -129,6 +131,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); + // Configure subdev + if (vm.count("subdev")) { + usrp->set_tx_subdev_spec(subdev); + usrp->set_rx_subdev_spec(subdev); + } + UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl; + serial = get_serial(usrp, "tx"); + UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl; + //set the antennas to cal if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){ throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate."); @@ -158,6 +169,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if (not vm.count("freq_start")) freq_start = usrp->get_rx_freq_range().start() + 50e6; if (not vm.count("freq_stop")) freq_stop = usrp->get_rx_freq_range().stop() - 50e6; + UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl; for (double rx_lo_i = freq_start; rx_lo_i <= freq_stop; rx_lo_i += freq_step){ const double rx_lo = tune_rx_and_tx(usrp, rx_lo_i, tx_offset); @@ -238,7 +250,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ threads.interrupt_all(); threads.join_all(); - store_results(usrp, results, "RX", "rx", "iq"); + store_results(results, "RX", "rx", "iq", serial); return EXIT_SUCCESS; } diff --git a/host/utils/uhd_cal_tx_dc_offset.cpp b/host/utils/uhd_cal_tx_dc_offset.cpp index c9cf757f4..eb82db826 100644 --- a/host/utils/uhd_cal_tx_dc_offset.cpp +++ b/host/utils/uhd_cal_tx_dc_offset.cpp @@ -20,6 +20,7 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/utils/paths.hpp> #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/msg.hpp> #include <uhd/usrp/multi_usrp.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> @@ -94,7 +95,7 @@ static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double tx_l * Main **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ - std::string args; + std::string args, subdev, serial; double tx_wave_freq, tx_wave_ampl, rx_offset; double freq_start, freq_stop, freq_step; size_t nsamps; @@ -104,6 +105,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("help", "help message") ("verbose", "enable some verbose") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") + ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')") ("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz") ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts") ("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz") @@ -131,6 +133,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); + // Configure subdev + if (vm.count("subdev")) { + usrp->set_tx_subdev_spec(subdev); + usrp->set_rx_subdev_spec(subdev); + } + UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl; + serial = get_serial(usrp, "tx"); + UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl; + //set the antennas to cal if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){ throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate."); @@ -160,6 +171,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6; if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6; + UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl; for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){ const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset); @@ -235,7 +247,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ threads.interrupt_all(); threads.join_all(); - store_results(usrp, results, "TX", "tx", "dc"); + store_results(results, "TX", "tx", "dc", serial); return EXIT_SUCCESS; } diff --git a/host/utils/uhd_cal_tx_iq_balance.cpp b/host/utils/uhd_cal_tx_iq_balance.cpp index 20d018edf..786aac061 100644 --- a/host/utils/uhd_cal_tx_iq_balance.cpp +++ b/host/utils/uhd_cal_tx_iq_balance.cpp @@ -20,6 +20,7 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/utils/paths.hpp> #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/msg.hpp> #include <uhd/usrp/multi_usrp.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> @@ -95,7 +96,7 @@ static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double tx_l * Main **********************************************************************/ int UHD_SAFE_MAIN(int argc, char *argv[]){ - std::string args; + std::string args, subdev, serial; double tx_wave_freq, tx_wave_ampl, rx_offset; double freq_start, freq_stop, freq_step; size_t nsamps; @@ -105,6 +106,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("help", "help message") ("verbose", "enable some verbose") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") + ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')") ("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz") ("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts") ("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz") @@ -122,7 +124,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if (vm.count("help")){ std::cout << boost::format("USRP Generate TX IQ Balance Calibration Table %s") % desc << std::endl; std::cout << - "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n" + "This application measures leakage between RX and TX on a daughterboard to self-calibrate.\n" << std::endl; return EXIT_FAILURE; } @@ -132,6 +134,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); + // Configure subdev + if (vm.count("subdev")) { + usrp->set_tx_subdev_spec(subdev); + usrp->set_rx_subdev_spec(subdev); + } + UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl; + serial = get_serial(usrp, "tx"); + UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl; + //set the antennas to cal if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){ throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate."); @@ -161,6 +172,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6; if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6; + UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl; for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){ const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset); @@ -241,7 +253,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ threads.interrupt_all(); threads.join_all(); - store_results(usrp, results, "TX", "tx", "iq"); + store_results(results, "TX", "tx", "iq", serial); return EXIT_SUCCESS; } + diff --git a/host/utils/usrp_cal_utils.hpp b/host/utils/usrp_cal_utils.hpp index 40626dfaa..5aff5e22f 100644 --- a/host/utils/usrp_cal_utils.hpp +++ b/host/utils/usrp_cal_utils.hpp @@ -179,27 +179,37 @@ static inline void write_samples_to_file( outfile.close(); } + /*********************************************************************** - * Store data to file + * Retrieve d'board serial **********************************************************************/ -static void store_results( +static std::string get_serial( uhd::usrp::multi_usrp::sptr usrp, - const std::vector<result_t> &results, - const std::string &XX, - const std::string &xx, - const std::string &what + const std::string &tx_rx ){ - //extract eeprom serial uhd::property_tree::sptr tree = usrp->get_device()->get_tree(); - const uhd::fs_path db_path = "/mboards/0/dboards/A/" + xx + "_eeprom"; + uhd::usrp::subdev_spec_t subdev_spec = usrp->get_rx_subdev_spec(); + const uhd::fs_path db_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/" + tx_rx + "_eeprom"; const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get(); + return db_eeprom.serial; +} +/*********************************************************************** + * Store data to file + **********************************************************************/ +static void store_results( + const std::vector<result_t> &results, + const std::string &XX, // "TX" or "RX" + const std::string &xx, // "tx" or "rx" + const std::string &what, // Type of test, e.g. "iq", + const std::string &serial +){ //make the calibration file path fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd"; fs::create_directory(cal_data_path); cal_data_path = cal_data_path / "cal"; fs::create_directory(cal_data_path); - cal_data_path = cal_data_path / str(boost::format("%s_%s_cal_v0.2_%s.csv") % xx % what % db_eeprom.serial); + cal_data_path = cal_data_path / str(boost::format("%s_%s_cal_v0.2_%s.csv") % xx % what % serial); if (fs::exists(cal_data_path)){ fs::rename(cal_data_path, cal_data_path.string() + str(boost::format(".%d") % time(NULL))); } @@ -207,7 +217,7 @@ static void store_results( //fill the calibration file std::ofstream cal_data(cal_data_path.string().c_str()); cal_data << boost::format("name, %s Frontend Calibration\n") % XX; - cal_data << boost::format("serial, %s\n") % db_eeprom.serial; + cal_data << boost::format("serial, %s\n") % serial; cal_data << boost::format("timestamp, %d\n") % time(NULL); cal_data << boost::format("version, 0, 1\n"); cal_data << boost::format("DATA STARTS HERE\n"); @@ -259,3 +269,4 @@ static void capture_samples( throw std::runtime_error("did not get all the samples requested"); } } + |