/* Alibava control via Ethernet interface */ /* Copyright I.Tsurin Liverpool University V2.0 (05.05.2015) */ /* */ /* http://www.alibavasystems.com */ /* Acknowledgment: Paulo Pedreiras, Out.2005 RCAI 05/06 */ /* http://www.ieeta.pt/~pedreiras/resources/rcai/raw-sr.c */ /* Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // the L2 protocols #include #define DEVICE "eth0" int s = 0; // Socket descriptor unsigned char *eth_head; // byte pointer to ethenet header unsigned char *eth_data; // byte pointer to ethernet data field struct ethhdr *eh; // structured pointer to ethernet header int eCommID; struct sockaddr_ll socket_address; void *buffer = NULL; void *cache = NULL; int Index = 0; /* Local host NIC MAC address */ unsigned char src_mac[6] = {0x00, 0x1D, 0x09, 0xB1, 0x46, 0x6F}; /* Front end address template */ unsigned char dest_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; void sigint(int signum); void eth_raw_init(); FILE *fr, *fw; /* Trigger Card controls */ #define HPlength 1326 #define RPlength 652 #define SPtime 160000000 #define Latency 7 #define MCA 0 // Rotary switch #define LU 2 // Locally administered unicast #define MC 0 #define MB 1 #define Reset 0x00 #define Write 0x01 #define Read 0x02 #define RunGo 0x03 #define Poll 0x04 /* Motherboard controls */ #define eCLK 0 #define iCLK 1 #define eTRG 0 #define iTRG 1 #define eRUN 0 #define iRUN 1 #define dCAL 0 #define eCAL 1 #define pDV 0 #define nDV 1 #define dDV0 0 #define eDV0 1 #define dDV1 0 #define eDV1 1 #define eRAM 0 #define dRAM 1 #define CRoctet(RAM, DV1, DV0, PHY, CAL, RUN, TRG, CLK) \ ((RAM & 0x01)<<7 | (DV1 & 0x01)<<6 | (DV0 & 0x01)<<5 | (PHY & 0x01)<<4 | \ (CAL & 0x01)<<3 | (RUN & 0x01)<<2 | (TRG & 0x01)<<1 | CLK & 0x01) /* DAC controls */ #define SDI0 0 #define SDI1 1 #define CLK0 0 #define CLK1 1 #define nCS0 0 #define nCS1 1 #define nLD0 0 #define nLD1 1 #define nRS0 0 #define nRS1 1 #define Tcode(Tvalue) (int)(4095.*(Tvalue + 5.- 2.048)/5.) #define DACoctet(nRS, nLD, nCS, CLK, Dbit) \ ((nRS & 0x01)<<4 | (nLD & 0x01)<<3 | (nCS & 0x01)<<2 | (CLK & 0x01)<<1 | (Dbit & 0x01)) /* Beetle controls */ #define SCL0 0 #define SCL1 1 #define SDA0 0 #define SDA1 1 #define RW0 0 #define RW1 1 /* Bit0: SDA Bit1: SCL Bit2: SDA direction (Read '1' / Write '0') Bit3: Reset (after programming latency) Bits 4..6 bit select for acknowledge word Bit7: Strobe to latch SDA state for register readout */ #define ASICoctet(STB, Code, RES, RW, SCL, SDA) \ ((STB & 0x01)<<7 | (Code & 0x07)<<4 | (RES & 0x01)<<3 | (RW & 0x01)<<2 | (SCL & 0x01)<<1 | (SDA & 0x01)) /* Motherboard Commands */ #define iniCTR 0x00 #define comREG 0x01 #define iniDAC 0x02 #define iniASIC 0x03 #define iniDEL 0x04 #define iniBUF 0x05 #define iniTDC 0x06 #define iniSTA 0x09 #define iniMOD 0x0A #define MODset 0x27 /* Delay controls */ #define SI0 0 #define SI1 1 #define SC0 0 #define SC1 1 #define AE0 0 #define AE1 1 #define DELoctet(AE, SC, Dbit) \ ((AE & 0x01)<<2 | (SC & 0x01)<<1 | (Dbit & 0x01)) /* TDC controls */ #define CSN0 0 #define CSN1 1 #define ALE0 0 #define ALE1 1 #define RDN0 0 #define RDN1 1 #define WRN0 0 #define WRN1 1 #define TDCoctet(RW, WRN, RDN, ALE, CSN) \ ((RW & 0x01)<<4 | (WRN & 0x01)<<3 | (RDN & 0x01)<<2 | (ALE & 0x01)<<1 | (CSN & 0x01)) /* default settings */ int MBset[] = { /* control register */ 0x30, /* threshold DACs 863 */ 0x843, 0x843, 0xFFF, 0x843, /* ASIC 0 settings: 1st octet is I2C geoAddress */ 0x20, 20, 0, 0x00, 1, 0x4B, 2, 0x0A, 3, 0x0A, 4, 0x1F, 5, 0x66, 6, 0x05, 7, 0x00, 8, 0x00, 9, 0x00, 10, 0x0D, 11, 0x8C, 12, 0x6B, 13, 0x1D, 14, 0x1D, 15, 0x77, 16, 0x10, 17, 0x1A, 18, 0x02, 19, 0x09, /* ASIC 1 settings: 1st octet is I2C geoAdress */ 0x21, 20, 0, 0x00, 1, 0x4B, 2, 0x0A, 3, 0x0A, 4, 0x1F, 5, 0x66, 6, 0x05, 7, 0x00, 8, 0x00, 9, 0x00, 10, 0x0D, 11, 0x8C, 12, 0x6B, 13, 0x1D, 14, 0x1D, 15, 0x77, 16, 0x10, 17, 0x1A, 18, 0x02, 19, 0x09, }; /* ****************/ /* Formatting */ /* ****************/ const char *byte_to_binary(unsigned char x) { static char b[9]; b[0] = '\0'; int i; for (i=256; i>0; i>>=1) strcat(b, ((x & i) == i) ? "1" : "0"); return b; } unsigned int htoi (const char *ptr) { unsigned int val = 0; char ch = *ptr; while (ch == ' ' || ch == '\t') ch = *(++ptr); for (;;) { if (ch >= '0' && ch <= '9') val = (val << 4) + (ch - '0'); else if (ch >= 'A' && ch <= 'F') val = (val << 4) + (ch - 'A' + 10); else if (ch >= 'a' && ch <= 'f') val = (val << 4) + (ch - 'a' + 10); else return val; ch = *(++ptr); } } unsigned int dtoi (const char *ptr) { unsigned int val = 0; char ch = *ptr; while (ch == ' ' || ch == '\t') ch = *(++ptr); for (;;) { if (ch >= '0' && ch <= '9') val = (val * 10) + (ch - '0'); else return val; ch = *(++ptr); } } int Hget(int Inc, int Length) { unsigned char SYM[4]; Index += Inc; memset(SYM, '\00', 4); memcpy(SYM, cache+Index, Length); return htoi(SYM); } int Dget(int Inc, int Length) { unsigned char SYM[4]; Index += Inc; memset(SYM, '\00', 4); memcpy(SYM, cache+Index, Length); return dtoi(SYM); } /***************************************/ /* Ethernet packet sender */ /***************************************/ void PING(int Device, int Address, int Command, int Abyte, int Dbyte) { int i, Dsize; /* Re-build ethernet header */ dest_mac[0] = (unsigned char)( MCA<<4 | Device<<3 | LU)&0xFF; dest_mac[1] = (unsigned char)(Address<<4 | Command)&0xFF; eCommID = ((int)dest_mac[0])<<8 | ((int)dest_mac[1])&0xF3; memcpy((void *)eh->h_dest, (void*)dest_mac, ETH_ALEN); memcpy((void *)eh->h_source,(void*)src_mac, ETH_ALEN); /* set pointer to beginning of the ethernet data field */ eth_data = buffer + ETH_HLEN; *(eth_data++) = (unsigned char)Abyte&0xFF; *(eth_data++) = (unsigned char)Dbyte&0xFF; Dsize = 2; /* Update data size */ eh->h_proto = htons(Dsize); /* Output data string */ i = sendto(s, buffer, (Dsize + ETHER_HDR_LEN), 0, ((struct sockaddr*)&socket_address), sizeof(socket_address)); if (i == -1) { perror("sendto():"); exit(1); } } /***************************************/ /* Threshold DACs */ /***************************************/ void wDACbit(int MBA, int Dbit) /* write bit */ { PING(MB, MBA, Write, iniDAC, DACoctet(nRS1, nLD1, nCS0, CLK0, Dbit)); PING(MB, MBA, Write, iniDAC, DACoctet(nRS1, nLD1, nCS0, CLK1, Dbit)); } void DACset(int MBA, int Chan, int Dbyte) { int i; printf("Load threshold 0x%03X\n", Dbyte); PING(MB, MBA, Write, iniDAC, DACoctet(nRS1, nLD1, nCS1, CLK1, SDI1)); // initial condition /* channel address */ for (i=0; i<2; i++) { int Dbit = (Chan>>(1-i)) & 0x01; wDACbit(MBA, Dbit); } /* don't care */ for (i=0; i<2; i++) { int Dbit = (Chan>>(1-i)) & 0x01; wDACbit(MBA, Dbit); } /* threshold value */ for (i=0; i<12; i++) { int Dbit = (Dbyte>>(11-i)) & 0x01; wDACbit(MBA, Dbit); } PING(MB, MBA, Write, iniDAC, DACoctet(nRS1, nLD1, nCS1, CLK1, SDI1)); // end of transfer PING(MB, MBA, Write, iniDAC, DACoctet(nRS1, nLD0, nCS1, CLK1, SDI1)); // activate settings PING(MB, MBA, Write, iniDAC, DACoctet(nRS1, nLD1, nCS1, CLK1, SDI1)); // complete } /***************************************/ /* ASIC configuration */ /***************************************/ void sASIC(int MBA) /* start I2C transmission */ { PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW1, SCL1, SDA1)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL1, SDA0)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL0, SDA0)); } void wASICbit(int MBA, int Dbit) /* write bit */ { PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL0, Dbit)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL1, Dbit)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL0, Dbit)); } void wASICbyte(int MBA, int Dbyte) /* write byte */ { int i; for (i=0; i<8; i++) { int Dbit = (Dbyte>>(7-i)) & 0x01; wASICbit(MBA, Dbit); } } void aASIC(int MBA, int Code) /* write byte acknowledge */ { PING(MB, MBA, Write, iniASIC, ASICoctet(0, Code, 0, RW1, SCL0, SDA0)); PING(MB, MBA, Write, iniASIC, ASICoctet(1, Code, 0, RW1, SCL1, SDA0)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, Code, 0, RW1, SCL0, SDA0)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL0, SDA0)); } void pASIC(int MBA) /* terminate I2C transmission */ { PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL0, SDA0)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL1, SDA0)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW0, SCL1, SDA1)); PING(MB, MBA, Write, iniASIC, ASICoctet(0, 0, 0, RW1, SCL1, SDA1)); } void rASICbyte(int MBA) { int Code; for (Code=0; Code<8; Code++) aASIC(MBA, Code); } void ASICwrite(int MBA, int ChipID, int Pointer, int *Dbyte) { sASIC(MBA); wASICbyte(MBA, ChipID<<1 | 0); // address and write command aASIC(MBA, 0); // acknowledge wASICbyte(MBA, Pointer); // set Beetle pointer aASIC(MBA, 0); // acknowledge if (Dbyte) // not sending data from NULL address { wASICbyte(MBA, *Dbyte); aASIC(MBA, 0); } pASIC(MBA); } void iASIC(int MBA) { PING(MB, MBA, Write, comREG, 0xAA); } /* ************* */ /* DEL controls */ /* ************* */ void DELset(int MBA, int Dbyte) { int i; PING(MB, MBA, Write, iniDEL, DELoctet(AE0, SC0, SI0)); // initial condition PING(MB, MBA, Write, iniDEL, DELoctet(AE1, SC0, SI0)); // initial condition for (i=0; i<8; i++) { int Dbit = (Dbyte>>(7-i)) & 0x01; PING(MB, MBA, Write, iniDEL, DELoctet(AE1, SC0, Dbit)); PING(MB, MBA, Write, iniDEL, DELoctet(AE1, SC1, Dbit)); } PING(MB, MBA, Write, iniDEL, DELoctet(AE1, SC0, SI0)); // final condition PING(MB, MBA, Write, iniDEL, DELoctet(AE0, SC0, SI0)); // complete } /***************************************/ /* ACAM TDC configuration */ /***************************************/ void TDCwrite(int MBA, int Abyte, int Dbyte) { PING(MB, MBA, Write, iniTDC, TDCoctet(RW1, WRN1, RDN1, ALE0, CSN1)); // initial condition PING(MB, MBA, Write, iniBUF, Abyte); // Address PING(MB, MBA, Write, iniTDC, TDCoctet(RW0, WRN1, RDN1, ALE1, CSN1)); PING(MB, MBA, Write, iniTDC, TDCoctet(RW0, WRN1, RDN1, ALE0, CSN1)); // latch address PING(MB, MBA, Write, iniBUF, Dbyte); // Data PING(MB, MBA, Write, iniTDC, TDCoctet(RW0, WRN1, RDN1, ALE0, CSN0)); // chip enable PING(MB, MBA, Write, iniTDC, TDCoctet(RW0, WRN0, RDN1, ALE0, CSN0)); PING(MB, MBA, Write, iniTDC, TDCoctet(RW0, WRN1, RDN1, ALE0, CSN0)); // latch data PING(MB, MBA, Write, iniTDC, TDCoctet(RW1, WRN1, RDN1, ALE0, CSN1)); // complete } /***************************************/ /* Ethernet packet receiver */ /***************************************/ int PONG(void) { int i; int TimeOut = 100; while(TimeOut) { int CommID; /* Read NC buffer */ i = recvfrom(s, buffer, ETH_DATA_LEN, 0, NULL, NULL); if (i == -1) { perror("recfrom():"); exit(1); } CommID = ((int)eh->h_source[0])<<8 | ((int)eh->h_source[1])&0xF3; if (CommID == eCommID) break; TimeOut--; } /* end while(TimeOut) */ return TimeOut; } /***************************************/ /* Wait for trigger */ /***************************************/ int wTrig(void) { int Stat; /* Request MC read */ PING(MC, 0, Poll, 0, 0); /* pause between send and receive ethernet packets (hardware needs 10us to receive and to retransmit) */ usleep(100); /* Fetch MC data */ if (PONG()) { eth_data = buffer + ETH_HLEN; Stat = (int)(eth_data[0]&0x01); } else Stat = 0; usleep(1000); return Stat; } /***************************************/ /* main module */ /* */ /* send configuration to motherboard N */ /***************************************/ int main(int argc, char **argv) { int i, MBA, Chan, RunInd; int ChipID, Nparam; int Nevents = 0; char *Fname = "PED/teldat_ped_"; int aux=0; char Fname_aux[100]; long lSize; size_t result; char KazuName[50]; if ((argc==2) | (argc==3)) Nevents = atoi(argv[1]); if (argc==3) Fname = argv[2]; /* Create socket */ eth_raw_init(); buffer = (void*)malloc(ETHER_MAX_LEN); /* set structurised pointer to beginning of ethernet header */ eth_head = buffer; eh = (struct ethhdr *)eth_head; /* Configure Trigger card */ PING(MC, 0, Write, 0x05, 0); // Clear run number PING(MC, 0, Write, 0x06, 0); PING(MC, 0, Write, 0x07, Nevents>>24); // events to be processed during spill PING(MC, 0, Write, 0x08, Nevents>>16); PING(MC, 0, Write, 0x09, Nevents>>8); PING(MC, 0, Write, 0x0A, Nevents); PING(MC, 0, Write, 0x0B, SPtime>>24); // Spill duration in clock cycles PING(MC, 0, Write, 0x0C, SPtime>>16); PING(MC, 0, Write, 0x0D, SPtime>>8); PING(MC, 0, Write, 0x0E, SPtime); PING(MC, 0, Write, 0x0F, Latency); // Beetle trigger delay PING(MC, 0, Write, 0x10, 0x00); // RUN mode // PING(MC, 0, Write, 0x10, 0xFF); // Test mode /* Configure Motherboards */ for (MBA=0; MBA<5; MBA++) { int SRCset; printf("\n"); printf("Configure board %d:\n", MBA); sprintf (KazuName,"%s%i%s", "kazuXY", MBA, ".ini"); /* set pointer to beginning of the ASIC conf. data */ int *Value = MBset; fr=fopen(KazuName, "r"); if (fr==NULL) fputs ("no ini file found, use default settings", stderr); else { fseek (fr , 0 , SEEK_END); lSize = ftell (fr); rewind (fr); /* allocate buffer for the entire file */ cache = (void*)malloc(sizeof(unsigned char)*lSize); /* copy the entire file into buffer */ result = fread (cache, 1, lSize, fr); fclose(fr); Index = 0; /* get the control register value */ *Value++ = Hget(25, 2); /* get the trigger threshold value */ *Value++ = Hget(27, 3); /* get the reset pulse threshold value */ *Value++ = Hget(7, 3); /* get the clock negative threshold value */ *Value++ = Hget(7, 3); /* get the clock positive threshold value */ *Value++ = Hget(7, 3); /* get the ASIC I2C GA */ *Value++ = Hget(58, 2); /* get the number of ASIC control registers */ *Value++ = Nparam = Dget(4, 2); for (i=0; i>8); // length of ethernet packet (payload) PING(MC, 0, Write, 0x04, HPlength); PING(MC, 0, RunGo, 0, 0); /* Wait for Trigger */ while(wTrig()==0); /* Dump MC data */ RunInd = ((int)eth_data[1])<<8 | (int)eth_data[2]; sprintf (Fname_aux, "%s%s%i%s", "./", Fname, RunInd, ".bin"); printf("run index %d file %s\n", RunInd, Fname_aux); fw=fopen(Fname_aux, "w+"); fwrite(eth_data, 1, HPlength, fw); // header with scalers and temperatures /* Init event size */ PING(MC, 0, Write, 0x01, Nevents>>8); // # of ethernet packets to be readout PING(MC, 0, Write, 0x02, Nevents); PING(MC, 0, Write, 0x03, RPlength>>8); // length of ethernet packet (payload) PING(MC, 0, Write, 0x04, RPlength); /* cyclic read of all boards */ for (MBA=0; MBA<5; MBA++) { /* Copy run number into MB */ PING(MB, MBA, Write, 0x07, RunInd>>8); PING(MB, MBA, Write, 0x08, RunInd); /* Request MB read */ PING(MB, MBA, Read, 0, 0); /* Fetch MB data packets */ i = 0; while(ih_source, 1, 6, fw); fwrite(eth_data, 1, RPlength, fw); i++; } /* end if(PONG) */ } /* end while (Nevents) */ /* Clear event counters */ PING(MB, MBA, Write, comREG, 0x55); } /* end for(MBA) */ fclose(fw); } /* end while */ return 0; } /* end main */ /***************************************/ /* eth_raw_init */ /***************************************/ void eth_raw_init() { int i; struct ifreq ifr; int ifindex = 0; // Ethernet Interface index /* Open socket */ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (s == -1) { perror("socket():"); exit(1); } printf("Successfully opened socket: %i\n", s); /*Get ethernet interface index */ strncpy(ifr.ifr_name, DEVICE, IFNAMSIZ); if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) { perror("SIOCGIFINDEX"); exit(1); } ifindex = ifr.ifr_ifindex; printf("Successfully got interface index: %i\n", ifindex); /* retrieve corresponding MAC */ if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) { perror("SIOCGIFINDEX"); exit(1); } for (i=0; i<6; i++) src_mac[i] = ifr.ifr_hwaddr.sa_data[i]; printf("Host MAC address: "); for (i=0; i<6; i++) printf("%02X:", src_mac[i]); printf("\n"); /* prepare sockaddr_ll */ socket_address.sll_family = PF_PACKET; socket_address.sll_protocol = 0x00; socket_address.sll_ifindex = ifindex; socket_address.sll_pkttype = PACKET_BROADCAST; socket_address.sll_halen = ETH_ALEN; socket_address.sll_addr[0] = dest_mac[0]; socket_address.sll_addr[1] = dest_mac[1]; socket_address.sll_addr[2] = dest_mac[2]; socket_address.sll_addr[3] = dest_mac[3]; socket_address.sll_addr[4] = dest_mac[4]; socket_address.sll_addr[5] = dest_mac[5]; socket_address.sll_addr[6] = 0x00; socket_address.sll_addr[7] = 0x00; /* establish signal handler */ signal(SIGINT, sigint); printf("Established signal handler for SIGINT\n"); } /***************************************/ /* Socket Terminator */ /***************************************/ void sigint(int signum) { struct ifreq ifr; if (s == -1) return; // No socket has beeen created strncpy(ifr.ifr_name, DEVICE, IFNAMSIZ); ioctl(s, SIOCGIFFLAGS, &ifr); ifr.ifr_flags &= ~IFF_PROMISC; ioctl(s, SIOCSIFFLAGS, &ifr); close(s); // free(cache); free(buffer); // fclose(fr); // fclose(fw); printf("Client terminating...\n"); exit(0); }