/********************************************************************\ Name: scs_210_celeroton.c Created by: Frank Meier & Stefan Ritt Contents: Application specific (user) part of Midas Slow Control Bus protocol for SCS-210 RS232 node connected to Celeroton CC-230-3500 power converter for the Mu3e 2g/s helium compressor \********************************************************************/ #include #include #include // for atof() #include #include "mscbemb.h" extern unsigned char xdata * xdata rbuf_rp; extern unsigned char xdata * xdata rbuf_wp; extern char xdata rbuf[2048]; char code node_name[] = "CLRTN01"; /* declare number of sub-addresses to framework */ unsigned char idata _n_sub_addr = 1; sbit CTS = P0 ^ 7; sbit RTS = P0 ^ 6; unsigned char xdata update_flag[13]; /*---- Define channels and configuration parameters returned to the CMD_GET_INFO command ----*/ /* data buffer (mirrored in EEPROM) */ struct { unsigned char on; unsigned long rpm_demand; unsigned long rpm_measured; unsigned char ack_error; unsigned long status; float temp_converter; float temp_motor; float current_motor; float voltage_motor; float power_motor; long int errorcode_1; long int errorcode_2; long int warningcode; long int infocode; unsigned char d[16]; } xdata user_data; MSCB_INFO_VAR code vars[] = { 1, UNIT_BOOLEAN,0, 0, 0, "On", &user_data.on, 4, UNIT_RPM, 0, 0, 0, "RpmDmd", &user_data.rpm_demand, 4, UNIT_RPM , 0, 0, 0, "RpmMeas", &user_data.rpm_measured, 1, UNIT_BOOLEAN,0, 0, 0, "AckErr", &user_data.ack_error, 4, UNIT_DWORD, 0, 0, 0, "Status", &user_data.status, 4, UNIT_CELSIUS,0, 0, MSCBF_FLOAT, "TConv", &user_data.temp_converter, 4, UNIT_CELSIUS,0, 0, MSCBF_FLOAT, "TMotor", &user_data.temp_motor, 4, UNIT_AMPERE, 0, 0, MSCBF_FLOAT, "IMotor", &user_data.current_motor, 4, UNIT_VOLT, 0, 0, MSCBF_FLOAT, "VMotor", &user_data.voltage_motor, 4, UNIT_WATT, 0, 0, MSCBF_FLOAT, "PMotor", &user_data.power_motor, 4, UNIT_DWORD, 0, 0, 0, "ErrCode1", &user_data.errorcode_1, // 32 bit error flags, 4, UNIT_DWORD, 0, 0, 0, "ErrCode2", &user_data.errorcode_2, // see compressor manual 4, UNIT_DWORD, 0, 0, 0, "WarnCode", &user_data.warningcode, 4, UNIT_DWORD, 0, 0, 0, "InfoCode", &user_data.infocode, 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d0", &user_data.d[0], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d1", &user_data.d[1], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d2", &user_data.d[2], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d3", &user_data.d[3], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d4", &user_data.d[4], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d5", &user_data.d[5], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d6", &user_data.d[6], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d7", &user_data.d[7], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d8", &user_data.d[8], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d9", &user_data.d[9], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d10", &user_data.d[10], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d11", &user_data.d[11], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d12", &user_data.d[12], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d13", &user_data.d[13], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d14", &user_data.d[14], 1, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "d15", &user_data.d[15], 0 }; MSCB_INFO_VAR *variables = vars; /********************************************************************\ Application specific init and inout/output routines \********************************************************************/ void user_write(unsigned char channel) reentrant; void write_gain(void); void putb(unsigned char *buf, unsigned char len); int getb(unsigned char *buf); void clear_rbuf(void); char xdata tx_buf[20]; char xdata rx_buf[20]; /*---- User init function ------------------------------------------*/ void user_init(unsigned char init) { unsigned char i; if (init) { user_data.rpm_demand = 0; user_data.on = 0; } user_data.status = 0; user_data.errorcode_1 = 0; user_data.errorcode_2 = 0; user_data.warningcode = 0; user_data.infocode = 0; for (i=0 ; i 0x12) // 0x12 is the longest expected response per the manual return -1; // checksum NOTE: The Celertoton manual has an error in the // code example. The length byte must be included in the calculation cs = rx_buf[0]; for(i=1 ; i < len ; i++) { rx_buf[i] = getbyte_wait(10); cs += rx_buf[i]; } cs = ~cs+1; // calculate checksum cs_rx = getbyte_wait(10); // checksum from transmission rx_buf[i] = cs_rx; led_blink(0, 1, 50); return (cs == cs_rx) ? len : -1; // len if checksums match, else -1 } // Convert 2 bytes in a char array to 32-bit int short int char2int16(unsigned char *buf) { return ((unsigned short int)buf[0]) + ((unsigned short int)buf[1] << 8); } // Convert 4 bytes in a char array to 32-bit int long int char2int32(unsigned char *buf) { return ((unsigned long int)buf[0]) + ((unsigned long int)buf[1] << 8) + ((unsigned long int)buf[2] << 16) + ((unsigned long int)buf[3] << 24); } void cel_get_status() { int len = 0; // send get status command tx_buf[0] = 0x02; // length tx_buf[1] = 0x00; // command // checksum tx_buf[2] = tx_buf[0] + tx_buf[1]; tx_buf[2] = ~tx_buf[2]+1; putb(tx_buf, 3); // receive and interprete status len = getb_celeroton(); if (len > 0) { user_data.errorcode_1 = char2int32(rx_buf+2); user_data.errorcode_2 = char2int32(rx_buf+6); user_data.warningcode = char2int32(rx_buf+10); user_data.infocode = char2int32(rx_buf+14); // 0x0080'0000 means hardwar DISABLE user_data.status = user_data.errorcode_2; } } short cel_read_value16(unsigned char flag) { unsigned char len; // send ReadValue command tx_buf[0] = 0x03; // length tx_buf[1] = 0x04; // command tx_buf[2] = flag; // variable index // checksum tx_buf[3] = tx_buf[0] + tx_buf[1] + tx_buf[2]; tx_buf[3] = ~tx_buf[3]+1; putb(tx_buf, 4); // receive and interprete variable len = getb_celeroton(); if (len >= 5) { user_data.ack_error = 0; return char2int16(rx_buf+3); } user_data.ack_error = 1; return 0; } long cel_read_value32(unsigned char flag) { unsigned char len; // send ReadValue command tx_buf[0] = 0x03; // length tx_buf[1] = 0x04; // command tx_buf[2] = flag; // variable index // checksum tx_buf[3] = tx_buf[0] + tx_buf[1] + tx_buf[2]; tx_buf[3] = ~tx_buf[3]+1; putb(tx_buf, 4); // receive and interprete variable len = getb_celeroton(); if (len >= 7) { user_data.ack_error = 0; return char2int32(rx_buf+3); } user_data.ack_error = 1; return 0; } void cel_write_value32(unsigned char flag, long value) { unsigned char i; // send ReadValue command tx_buf[0] = 0x08; // length tx_buf[1] = 0x05; // command tx_buf[2] = flag; // variable index tx_buf[3] = 0x03; // type = int32 tx_buf[4] = (value >> 0) & 0xFF; tx_buf[5] = (value >> 8) & 0xFF; tx_buf[6] = (value >> 16) & 0xFF; tx_buf[7] = (value >> 24) & 0xFF; // checksum tx_buf[8] = 0; for (i=0 ; i<8 ; i++) tx_buf[8] += tx_buf[i]; tx_buf[8] = ~tx_buf[8]+1; putb(tx_buf, 9); // receive acknowledge getb_celeroton(); } void cel_ack_error() { unsigned char i; memset(tx_buf, 0, sizeof(tx_buf)); memset(rx_buf, 0, sizeof(rx_buf)); // send AckError command tx_buf[0] = 0x0A; // length tx_buf[1] = 0x01; // command tx_buf[2] = (user_data.errorcode_1 >> 0) & 0xFF; tx_buf[3] = (user_data.errorcode_1 >> 8) & 0xFF;; tx_buf[4] = (user_data.errorcode_1 >> 16) & 0xFF;; tx_buf[5] = (user_data.errorcode_1 >> 24) & 0xFF;; tx_buf[6] = (user_data.errorcode_2 >> 0) & 0xFF; tx_buf[7] = (user_data.errorcode_2 >> 8) & 0xFF;; tx_buf[8] = (user_data.errorcode_2 >> 16) & 0xFF;; tx_buf[9] = (user_data.errorcode_2 >> 24) & 0xFF;; //for (i=2 ; i<10 ; i++) // tx_buf[i] = 0xFF; // checksum tx_buf[10] = 0; for (i=0 ; i<10 ; i++) tx_buf[10] += tx_buf[i]; tx_buf[10] = ~tx_buf[10]+1; putb(tx_buf, 11); // receive acknowledge getb_celeroton(); //for (i=0 ; i<16 ; i++) // user_data.d[i] = rx_buf[i]; } void cel_start(unsigned char flag) { if (flag) { // start tx_buf[0] = 0x02; // length tx_buf[1] = 0x02; // command tx_buf[2] = 0xFC; // checksum putb(tx_buf, 3); } else { // stop tx_buf[0] = 0x02; // length tx_buf[1] = 0x03; // command tx_buf[2] = 0xFB; // checksum putb(tx_buf, 3); } // receive acknowledge getb_celeroton(); } /*---- User loop function ------------------------------------------*/ unsigned long xdata last_read = 0; void user_loop(void) { if (update_flag[0]) { update_flag[0] = 0; led_blink(1, 2, 50); // set demand RPM cel_write_value32(0, user_data.rpm_demand); // turn celeroton on/off cel_start(user_data.on); } if (update_flag[1]) { update_flag[1] = 0; led_blink(1, 2, 50); // set demand RPM cel_write_value32(0, user_data.rpm_demand); } if (update_flag[9] || update_flag[10]) { update_flag[9] = 0; update_flag[10] = 0; led_blink(1, 2, 50); // acknowledge error cel_ack_error(); } /* read parameters once each second */ if (time() > last_read + 100) { // clear any stuck data clear_rbuf(); cel_get_status(); user_data.rpm_measured = cel_read_value32(0x01); user_data.temp_converter = (float)cel_read_value16(0x04); user_data.temp_motor = (float)cel_read_value16(0x08); user_data.current_motor = (float)cel_read_value16(0x02) / 1000.0; user_data.voltage_motor = (float)cel_read_value16(0x05); user_data.power_motor = (float)cel_read_value16(0x06); last_read = time(); } }