Mauricio Donatti / Mbed 2 deprecated DCM_Heaters_8CH_v2

Dependencies:   mbed mbed-rtos AMC7812B EthernetInterface TextLCD

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*********************************************************************
00002 *
00003 * Driver Heaters DCM 8 channel - v4 (improvements)
00004 * 
00005 * Mauricio Martins Donatti
00006 * mauricio.donatti@lnls.br
00007 *
00008 * Electronic Support Group - GAE
00009 * Brazilian Synchrotron Light Laboratory (LNLS)
00010 * Brazilian Center for Research in Energy and Materials (CNPEM)
00011 *
00012 * Jan 2021
00013 *
00014 * References:
00015 *   - AMC7812B datasheet: http://www.ti.com/lit/ds/symlink/amc7812b.pdf
00016 *   - Modification inside ethernet library: https://os.mbed.com/questions/1602/How-to-set-the-TCPIP-stack-s-hostname-pr/
00017 *   - VERY IMPORTANT: https://os.mbed.com/questions/61544/threaded-TCP-server-with-multi-port-it-r/
00018 *
00019 *******************************************************************/
00020 
00021 #define SUPPLY_24V
00022 //#define CAL
00023 
00024 #include "mbed.h"
00025 #include "TextLCD.h"
00026 #include "EthernetInterface.h"
00027 #include "amc7812b.h"
00028 
00029 #define ERROR_INTERFACE
00030 //#define DEBUG_INTERFACE
00031 
00032 #include "definitions.h"
00033 #include "HTTP_SERVER.h"
00034 
00035 #define VERSION             "v4.1-2021-07\0"        //Firmware Version
00036 #define DEVICE_NAME         "DH-8CH-001\0"          //Device Name - Ethernet default hostname
00037  
00038 #define PORT    6767                                //Socket Port (EPICS data)
00039 
00040 //SPI constructor
00041 SPI spi(MOSI,MISO,SCLK);                            //mosi, miso, sclk
00042 
00043 Serial pc(USBTX, USBRX, 115200);
00044 
00045 //Digital Output constructors
00046 DigitalOut cs_u4(CS_U4);
00047 DigitalOut cs_u5(CS_U5);
00048 DigitalOut amc_reset(RST);
00049 DigitalOut dac_clr(DAC_CLR);
00050 DigitalOut cnvt_u5(CNVT_U5);
00051 DigitalOut cnvt_u4(CNVT_U4);
00052 
00053 //Digital Input constructors
00054 DigitalIn al_u4(AL_U4);
00055 DigitalIn al_u5(AL_U5);
00056 
00057 //Interrupt Input constructors
00058 InterruptIn dav_u4(DAV_U4);
00059 InterruptIn dav_u5(DAV_U5);
00060  
00061 //Digital output indicators
00062 DigitalOut blink(LED4);                 //Heartbeat at LED4
00063 DigitalOut socket_led(LED2);            //Socket Connection LED
00064 DigitalOut led_cfg(LED3);               //Configuration LED - ON only in configuration mode (adjusting current limit)
00065 DigitalOut server_led(LED1);            //HTTP Server LED
00066 DigitalOut phy_rst(P1_28);              //Ethernet PHY reset
00067 DigitalOut eth_led1(p29);                //Ethernet LED1
00068 DigitalOut eth_led2(p30);                //Ethernet LED2
00069 
00070 //LCD Construtor
00071 Serial display(LCD_TX, LCD_RX);       //LCD module initialization
00072 
00073 //Timer Tickers 
00074 Ticker start_convertion;            //Triggers ADC convertion
00075 Timer t;                            //read ms timer to display and heartbeat functions
00076 
00077 //There is a configuration file that can be accessed through usb in order to adjust current limits
00078 LocalFileSystem local("local");     //Create the local filesystem under the name "local"
00079 
00080 //Variable Initialization
00081 EthernetInterface eth;              //ethernet interface
00082 TCPSocketServer server;             //Socket
00083 TCPSocketConnection client;         //Client
00084 
00085 //Create the variables structure for 8 channels (index 0 to 7) 
00086 channel CH[8];
00087 
00088 //Create two spi global buffers - tx and rx
00089 //LPC1768 SPI works in 12 bits. AMC7812B spi works in 24 bits.
00090 union spi_buf{          //the same buffer may be expressed in two bytes (uint8_t) or a 16bit word (uint16_t)
00091     uint8_t byte[2];
00092     uint16_t data;
00093 }rx,tx;
00094 
00095 FILE *cfg_file;             //Config file variable
00096 FILE *html_file;            //Html file variable
00097     
00098 int tmp,i;                                  //auxiliary integers
00099 int LCD_index=0;                            //LCD index (displayed channel changes from 1 to 8)
00100 char LCD_buffer[40];                        //LCD char buffer    
00101 char cfg=0;                                 //variable to identify config mode (config mode = current limit adjust mode)
00102 float mult = 10;                            //multiplier used in config mode
00103 char flag_adj=0;                            //flag to indicate adjust/config mode
00104 //int r,c;                                    //auxiliary integers to LCD row and column       
00105 uint8_t flag_end_u4,flag_end_u5;            //flags to indicate AD end of convertion
00106 uint8_t register_amc;                       //8 bit variable to store AMC register to read/write
00107 uint16_t reg_aux;                           //Aux 16 bit variable used in spi read/write functions
00108 
00109 //global variables for socket message treatment
00110 int ch_msg_idx,n;
00111 char tmp_char;   
00112 float ilimit_msg;
00113 
00114 Thread main_thread,server_thread,socket_thread;         //threads instances
00115 Thread display_thread;                                  //display thread (v3)
00116 volatile uint8_t new_cfg;                               //new config to save to file
00117 uint8_t display_status;                                        
00118 uint8_t server_init=0,socket_init=0;                    //sockets init flags 
00119 
00120 HttpServer httpsvr;         //http server instance
00121     
00122 char socket_buffer[200];    //socket receive buffer
00123 char send_buffer[100];      //socket send buffer
00124 
00125 int receive_return;         //receive return for socket loop thread
00126 
00127 char dev_name[30];          //device name string
00128 
00129 //Display Functions
00130 void error(void);                   //Turn Red Led - Error Status
00131 void normal(void);                  //Turn Green Led - Normal Status     
00132 void disabled(void);                //Turn (Red + Green) - Channel disabled
00133 void write_LCD(void);               //Write to LCD Function
00134 void reset_config(void);            //Reset config buttons status
00135 void clear_lcd(void);               //Clear LCD Function
00136 void heart(void);                   //Toggle function to heartbeat
00137 
00138 //AMC7812B ADC and DAC functions
00139 void fast_read_U5(void);    //U5 SPI fast read (returns previous transfer result)
00140 void fast_read_U4(void);    //U4 SPI fast read (returns previous transfer result)
00141 void read_U5(void);         //U5 SPI simple read - Takes two times the fast read
00142 void read_U4(void);         //U4 SPI simple read - Takes two times the fast read
00143 void write_U5(void);        //U5 SPI write
00144 void write_U4(void);        //U4 SPI write
00145 
00146 void setup(void);           //Initialization (display and variables)
00147 void amc_setup(void);       //AMC7812B setup (U4 and U5)
00148 
00149 //Config and Output functions
00150 void adj_ilimit(int channel,float value);   //Adjust current limit
00151 void fail_out(int channel,int value);       //Set/Reset failure output
00152 
00153 //End of convertion interruptions
00154 void end_conv_u4(void);         //U4 end of convertion function (interruption called)          
00155 void end_conv_u5(void);         //U5 end of convertion function (interruption called)    
00156 
00157 //ADC convertion Trigger Functions
00158 void trigger_conv(void);        //Trigger convertion function (start U4 and U5 convertion) - Ticker called
00159 void trigger_u4(void);          //Trigger U4 only (not used)
00160 void trigger_u5(void);          //Trigger U5 only (not used)
00161 
00162 extern "C" void mbed_reset();   //mbed reset function
00163 
00164 void message_treatment(void);   //socket data received treatment
00165 
00166 //Sockets functions
00167 void socket_start();        //initiate socket instances
00168 void server_loop(void);     //Server threaded loop - Port 80
00169 void socket_loop(void);     //Socket threaded loop - Port 5757
00170 
00171 //Thread loops
00172 void main_loop(void);       //main thread (real-time priority) - deals with the AMC devices
00173 void display_loop(void);    //display update thread - deals with buttons and LCD (uart)
00174 
00175 volatile int save_cfg_time;
00176 
00177 char html_page[HTML_MAX_SIZE];
00178 int html_page_size;
00179 
00180 //main function
00181 int main() {    
00182     //heartbeat.attach(&heart,HEARTBEAT_DELAY);   //attach heartbeat ticker
00183     
00184     t.start();
00185     // Reading webserver file
00186     wait_ms(10);             //Wait powerup
00187     
00188     html_file = fopen("/local/index.htm","r");  // Open "index.html" on the local file system for reading
00189     if(html_file==NULL){  //If file doesnt exist
00190         html_page_size = sprintf(html_page,"ERROR: File Not Found");
00191         ERROR_PRINTF("index.htm file not found at local file system!");
00192         fclose(html_file);   //close html file
00193     }
00194     else
00195     {                 //File exists
00196         fseek(html_file, 0, SEEK_SET);  
00197         html_page_size = 0;
00198         while (!feof(html_file))
00199             html_page[html_page_size++]= getc(html_file);
00200         if(feof(html_file))
00201             html_page_size--;
00202         fclose(html_file);   //close html file
00203     }
00204     
00205     amc_setup();        //Setup AMC7812B
00206     setup();            //Initialize LCD and variables
00207     
00208     dav_u4.fall(&end_conv_u4);  //attach the address of the U4 end of convertion function to the falling edge
00209     dav_u5.fall(&end_conv_u5);  //attach the address of the U5 end of convertion function to the falling edge
00210 
00211     start_convertion.attach(&trigger_conv,CONV_DELAY);      //attach ticker to trigger convertions - USED ONLY IN DIRECT MODE
00212     //trigger_conv();                                       //Start convertion - USED ONLY IN AUTO MODE 
00213     
00214     if (0 == eth.init())//Use DHCP
00215     {
00216         eth.setName(dev_name);
00217         
00218     }
00219     else {
00220         clear_lcd();
00221         display.printf("HW ERROR: eth conn");   //HW ethernet error - probably PHY broken
00222         ERROR_PRINTF("Ethernet Connection Hardware Error!");
00223         //Turn LED 1 Red and Green - ETH HW Error
00224         display.putc(0xFE);
00225         display.putc(0x5A);
00226         display.putc(0x01);
00227         display.putc(0x03);
00228     }
00229     main_thread.set_priority(osPriorityRealtime);   //Start AMCs thread with high high high priority
00230     server_thread.set_priority(osPriorityNormal);   //HTTP server thread normal priority
00231     socket_thread.set_priority(osPriorityNormal);   //Socket server (EPICS) normal priority
00232     display_thread.set_priority(osPriorityNormal);   //Socket server (EPICS) normal priority
00233 
00234     display_thread.start(display_loop);   //Start AMC loop
00235     main_thread.start(main_loop);   //Start AMC loop
00236    
00237     while(1)
00238     {       
00239             if(new_cfg==1 && t.read_ms() - save_cfg_time >= SAVE_CFG_DELAY_MIN)  //File must be saved by the main thread. new_cfg is a flag indicating new data mus be saved
00240             {
00241                 cfg_file = fopen("/local/lim.cfg", "w"); 
00242                                //Open "lim.cfg" on the local file system for writing
00243                 fprintf(cfg_file,"Channel Configuration - Current Limit and Enable\n");      //Write header
00244                 fprintf(cfg_file,"%s\n",dev_name);
00245                 for(tmp=0;tmp<8;tmp++)
00246                 {
00247                     fprintf(cfg_file,"%d %3.2f %d\n",tmp+1,CH[tmp].limit,CH[tmp].enable); //Write current limits to file
00248                 }
00249                 fclose(cfg_file);                                       //close file
00250                 new_cfg=0; //reset flag
00251             }
00252             if(eth.is_connected())  //if eth connected
00253             {
00254                 eth_led2 = !eth_led2;   //toggle led2
00255                 eth_led1 = 1;           //turn on led1
00256                 if(server_init == 0)    //initiate http server the first time
00257                 {
00258                     httpsvr.init(html_page,html_page_size); 
00259                     server_init = 1;    //turn flag on - Server initiated
00260                     server_thread.start(server_loop);   //run thread - monitoring port 80
00261                 }
00262                 if(socket_init == 0)    //initiate socket server (PORT 5757) - EPICS
00263                 {
00264                     socket_start();     
00265                     socket_init = 1;    //turn flag on
00266                     socket_thread.start(socket_loop);   //run thread - monitoring port 5757
00267                 }
00268             }                             
00269             else //connect ethernet
00270             {
00271                 if(eth_led1)    //eth_led serves also as flag
00272                 {
00273                     eth.disconnect();   //disconnect interface
00274                     eth_led1=0;         //turn leds off
00275                     eth_led2=0;
00276                     //Turn Display LED red
00277                     display.putc(0xFE);
00278                     display.putc(0x5A);
00279                     display.putc(0x01);
00280                     display.putc(0x02);
00281                 }
00282                 if (0 == eth.connect())   //once connected, display IP and hostname on LCD  
00283                 {
00284                     //Turn Display LED green
00285                     display.putc(0xFE);
00286                     display.putc(0x5A);
00287                     display.putc(0x01);
00288                     display.putc(0x01);
00289                 }
00290             }   
00291     }       
00292 }
00293 
00294 void display_loop(void)
00295 {
00296     int display_time,heart_time;
00297     char blink_led,byte_read;
00298     display_time = t.read_ms();
00299     heart_time = t.read_ms();
00300     blink_led = 0x01;
00301     while(1)
00302     {
00303         if(t.read_ms()- display_time >= DISPLAY_DELAY*1000)
00304         {
00305             display_time = t.read_ms();
00306             display_status = 0;
00307             if(cfg == 0)
00308             {                                   //If not in config mode
00309                 LCD_index = (LCD_index+1)%8;    //Update index
00310                 write_LCD();                    //call write_LCD()
00311             }
00312         }
00313         if(t.read_ms()- heart_time >= HEARTBEAT_DELAY*1000)
00314         {
00315             heart_time = t.read_ms();
00316             heart();
00317             display.putc(0xFE);
00318             display.putc(0x5A);
00319             display.putc(0x02);
00320             display.putc(blink_led);
00321             blink_led = blink_led ^ 0x01;   
00322         } 
00323         if(display.readable()) {
00324             byte_read = display.getc();
00325             if(byte_read=='B')//UP SQUARE BUTTON
00326             {
00327                 if(cfg==0)
00328                 {
00329                     display_time = t.read_ms();
00330                     display_status=1;
00331                     clear_lcd();
00332                     if(eth_led1 == 1)
00333                         display.printf("%-16s%-16s",eth.getIPAddress(),eth.getName());
00334                     else
00335                         display.printf("ETH DISCONNECTED");
00336                 }
00337                 else
00338                 {
00339                     reset_config();
00340                 }
00341             }
00342             if(byte_read=='A')//UP BUTTON
00343             {
00344                 display_status=0;
00345                 if(cfg==0)  //If not in CONFIG mode
00346                 {
00347                     display_time = t.read_ms();
00348                     clear_lcd();
00349                     LCD_index = (LCD_index+1)%8;                        //increment LCD index
00350                     write_LCD();                                        //write to LCD
00351                 }
00352                 else        //If CONFIG mode
00353                 {
00354                     if(CH[LCD_index].limit+mult <= CURR_MAX_LIMIT)          //Verify higher current bound condition
00355                         CH[LCD_index].limit = CH[LCD_index].limit + mult;   //Use multiplier to increment current 
00356                     display.putc(0xFE);
00357                     display.putc(0x47);
00358                     display.putc(0xC);
00359                     display.putc(0x2);
00360                     display.printf("%3.2f",CH[LCD_index].limit);
00361                     display.putc(0xFE);
00362                     display.putc(0x47);
00363                     if(cfg==1) //if config = 1, blink first digit
00364                         display.putc(0xB+cfg);
00365                     else        //else, blink second or third digit (after dot)
00366                         display.putc(0xC+cfg);
00367                     display.putc(0x2);
00368                 }
00369 
00370             }
00371             if(byte_read=='C')//DOWN BUTTON
00372             {
00373                 display_status=0;
00374                 if(cfg==0)  //If not in CONFIG mode
00375                 {
00376                     display_time = t.read_ms();
00377                     clear_lcd();
00378                     LCD_index = (LCD_index-1);                          //decrement LCD index                      
00379                     if(LCD_index==-1)                                   //Verify lower bound                
00380                         LCD_index = 7;
00381                     write_LCD();                                        //write to LCD
00382                 }
00383                 else        //If CONFIG mode
00384                 {
00385                     if(mult<=CH[LCD_index].limit)                           //Verify lower current bound condition
00386                         CH[LCD_index].limit = CH[LCD_index].limit - mult;   //Use multiplier to decrement current
00387                     display.putc(0xFE);
00388                     display.putc(0x47);
00389                     display.putc(0xC);
00390                     display.putc(0x2);
00391                     display.printf("%3.2f",CH[LCD_index].limit);
00392                     display.putc(0xFE);
00393                     display.putc(0x47);
00394                     if(cfg==1) //if config = 1, blink first digit
00395                         display.putc(0xB+cfg);
00396                     else        //else, blink second or third digit (after dot)
00397                         display.putc(0xC+cfg);
00398                     display.putc(0x2);
00399                 }
00400             }
00401             if(byte_read=='D')//DOWN SQUARE BUTTON
00402             {
00403                 if(cfg<4&&display_status==0)   //If CONFIG<4, go to next config
00404                 {
00405                     led_cfg=1;                                              //turn config led on
00406                     cfg = cfg++;                                            //increment config variable
00407                     mult = mult/10;                                         //adjust multiplier (divided by 10 each config increment)
00408                     display.putc(0xFE);
00409                     display.putc(0x47);
00410                     if(cfg==1) //if config = 1, blink first digit
00411                         display.putc(0xB+cfg);
00412                     else        //else, blink second or third digit (after dot)
00413                         display.putc(0xC+cfg);
00414                     display.putc(0x2);
00415                     display.putc(0xFE);
00416                     display.putc(0x53);
00417                 }
00418                 if(cfg>=4)  //If config >=4, configuration end
00419                 {
00420                     reset_config();
00421                 }    
00422             }
00423         } 
00424     }
00425 }
00426 
00427 void reset_config(void)
00428 {
00429     led_cfg=0;                                              //turn config led off
00430     cfg=0;                                                  //reset config variable    
00431     mult = 10;
00432                                                             //reset mult to standard value = 10
00433     adj_ilimit(LCD_index+1,CH[LCD_index].limit);            //adjust current limit
00434     
00435     new_cfg=1;
00436     save_cfg_time=t.read_ms();
00437     display.putc(0xFE);
00438     display.putc(0x54);
00439 }
00440 
00441 //message incoming treatment - Socket EPICS
00442 void message_treatment(void)
00443 {
00444     ch_msg_idx = socket_buffer[0] - 0x30;   //First character is the channel number
00445     if(ch_msg_idx>0 && ch_msg_idx<=8)       //drop if out of range
00446     {
00447         ch_msg_idx--;   //decrement to index 0 to 7
00448         if(socket_buffer[1]=='r')   //read message
00449         {
00450             n = sprintf(send_buffer,"OK>%d:\tV=%4.2f\tI=%3.2f\tC=%.1f\tIL=%3.2f\tF=%d\tOL=%d\tNL=%d\tE=%d\r\n",ch_msg_idx+1,\
00451                     CH[ch_msg_idx].voltage,CH[ch_msg_idx].current,\
00452                     CH[ch_msg_idx].control,CH[ch_msg_idx].limit,\
00453                     CH[ch_msg_idx].failure,CH[ch_msg_idx].overload>ERROR_REP,\
00454                     CH[ch_msg_idx].noload>ERROR_REP,CH[ch_msg_idx].enable);
00455             return;
00456         }
00457         if(socket_buffer[1]=='l') //current limit message
00458         {
00459             if(socket_buffer[2]=='?')   //get
00460             {
00461                 n = sprintf(send_buffer,"OK>%d:\tIL=%3.2f\r\n",ch_msg_idx+1,CH[ch_msg_idx].limit);   
00462                 return;
00463             }
00464             if(socket_buffer[3]=='.')   //set (must be in 3.2f format)
00465             {
00466                 ilimit_msg = (socket_buffer[2]-0x30) + (socket_buffer[4]-0x30)/10.0 + (socket_buffer[5]-0x30)/100.0;    //convert three digits to float
00467                 if(ilimit_msg > 0 && ilimit_msg <= CURR_MAX_LIMIT)  //verifiy bounds
00468                 {
00469                     CH[ch_msg_idx].limit = ilimit_msg;
00470                     ilimit_msg = ilimit_msg*I_K+I_OFF;              //Convert to voltage
00471                     do{
00472                         tx.data = int((0xFFF*ilimit_msg)/5)&0xFFF;      //Convert to 12 bit data
00473                         register_amc=DAC0+ch_msg_idx;                   //set register
00474                         write_U4();
00475                         read_U4();
00476                     }while(tx.data!=rx.data);   //try to write until success. (main thread also using SPI)
00477                     
00478                     n = sprintf(send_buffer,"OK>%d:\tIL=%3.2f\r\n",ch_msg_idx+1,CH[ch_msg_idx].limit);  
00479                     new_cfg=1;  //new cfg file must be written by the main loop
00480                     save_cfg_time = t.read_ms();
00481                     return;
00482                 }
00483                 else
00484                 {
00485                     n = sprintf(send_buffer,"ERROR>%5.2f out of range\r\n",ilimit_msg);   
00486                     return;
00487                 }
00488             }
00489         }
00490         if(socket_buffer[1]=='e') //enable message
00491         {
00492             if(socket_buffer[2]=='?')   //get method
00493             {
00494                 n = sprintf(send_buffer,"OK>%d:\tE=%d\r\n",ch_msg_idx+1,CH[ch_msg_idx].enable);   
00495                 return;
00496             }
00497             if(socket_buffer[2]=='1')   //set method (enable=1)
00498             {
00499                 do{
00500                 register_amc = GPIO;                        //set GPIO register
00501                 read_U5();                                  //read register
00502                 tx.data = rx.data | (0b1<<ch_msg_idx);
00503                 write_U5();                                 //write the 1 position
00504                 read_U5();
00505                 }while(tx.data != rx.data);     //try to write until success. (main thread also using SPI)                           
00506                 CH[ch_msg_idx].enable = 1;
00507                 new_cfg=1;
00508                 save_cfg_time=t.read_ms();
00509                 n = sprintf(send_buffer,"OK>%d:\tE=%d\r\n",ch_msg_idx+1,CH[ch_msg_idx].enable);   
00510                 return;
00511             }
00512             if(socket_buffer[2]=='0')    //set method (enable=0) - Disable
00513             {
00514                 do{
00515                     register_amc = GPIO;                        //set GPIO register
00516                     read_U5();                                  //read register
00517                     tx.data = rx.data & ~(0b1<<ch_msg_idx);
00518                     write_U5();                                 //write the 0 position
00519                     read_U5();                                 
00520                 }while(tx.data != rx.data);     //try to write until success. (main thread also using SPI)
00521                 CH[ch_msg_idx].enable = 0;
00522                 new_cfg=1;
00523                 save_cfg_time=t.read_ms();
00524                 n = sprintf(send_buffer,"OK>%d:\tE=%d\r\n",ch_msg_idx+1,CH[ch_msg_idx].enable);   
00525                 return;
00526             }
00527         }
00528     }
00529     if(socket_buffer[0]=='p'&&socket_buffer[1]=='i'&&socket_buffer[2]=='n'&&socket_buffer[3]=='g')  //ping message
00530     {
00531         n = sprintf(send_buffer,"OK>pong\r\n"); //answer pong
00532         return;    
00533     }
00534     if(socket_buffer[0]=='v')   //firmware version
00535     {
00536         n = sprintf(send_buffer,"OK>firmware version = %s\r\n",VERSION);
00537         return;    
00538     }
00539     if(socket_buffer[0]=='n')   //device name
00540     {
00541         if(socket_buffer[1]=='?')
00542         {
00543             n = sprintf(send_buffer,"OK>device name = %s\r\n",dev_name);
00544             return;    
00545         }
00546         if(socket_buffer[1]=='=')
00547         {
00548             n=0;
00549             while(socket_buffer[n+2]!='\0'&&n<=20)
00550             {
00551                 dev_name[n]=socket_buffer[n+2];
00552                 n++;   
00553             }
00554             dev_name[n]='\0';
00555             new_cfg=1;
00556             save_cfg_time=t.read_ms();
00557             n = sprintf(send_buffer,"OK>device name = %s\r\n",dev_name);
00558             return;    
00559         }
00560         
00561     }
00562     if(socket_buffer[0]=='r'&&socket_buffer[1]=='e'&&socket_buffer[2]=='s'&&socket_buffer[3]=='e'&&socket_buffer[4]=='t')   //reset messag
00563     {
00564         n = sprintf(send_buffer,"OK>rebooting...\r\n"); //answer
00565         client.send_all(send_buffer,n);
00566         wait_ms(500);
00567         mbed_reset();   //reset function
00568         return;    
00569     }     
00570     n = sprintf(send_buffer,"ERROR> NOT-A-CMD\r\n\0");  //command not found
00571 }
00572 
00573 void main_loop(void) //main thread (real-time priority) - read and write AMC devices
00574 {
00575     while(1){
00576         
00577         if(flag_end_u5)     //Wait U5 end of convertion
00578         {
00579             flag_end_u5 = 0;    //Reset flag
00580             
00581             register_amc = ADC0;    //reads U5 ADC0
00582             fast_read_U5();
00583             for(i=0;i<=7;i++)
00584             {
00585                 register_amc = ADC0+i+1;    //reads U5 ADC1 + i
00586                 fast_read_U5();
00587                 
00588                 CH[i].current = FILTC*CH[i].current + FILTC2*(((rx.data*5.0)/0xFFF)-I_OFF)/I_K; //store current of the previous channel
00589                 if(CH[i].current<0) //negative current not allowed
00590                     CH[i].current=0;
00591             }
00592             
00593         }
00594         
00595         if(flag_end_u4)     //Wait U4 end of convertion
00596         {   
00597             flag_end_u4 = 0;    //Reset flag 
00598                   
00599             register_amc = ADC0;    //reads U4 ADC0
00600             fast_read_U4();
00601             for(i=0;i<=7;i++)
00602             {
00603                 register_amc = ADC8+i;     //reads U4 ADC8 + i (ADC8 to ADC15)
00604                 fast_read_U4();
00605                 
00606                 CH[i].voltage = FILTC*CH[i].voltage+FILTC2*((rx.data*5.0)/0xFFF)/V_K; //store voltages (previous convertions - ADC0 to ADC7)
00607                 if(CH[i].voltage<0) //negative voltage not allowed
00608                     CH[i].voltage = 0;
00609                 
00610                 //Failure output triggered by NO LOAD or OVERLOAD
00611                 //Determine overload via software (above 90% current limit)
00612                 if(CH[i].current > CH[i].limit*0.85)
00613                 {
00614                     if(CH[i].overload<=2*ERROR_REP) //verify counter limit
00615                         CH[i].overload++;           //Increment overload counter    
00616                     if(CH[i].overload>=ERROR_REP)   //Digital Filtering by repetitive overload diagnostics
00617                         fail_out(i+1,1);            //Set failure output
00618                 }
00619                 else
00620                 {
00621                     if(CH[i].overload>0)
00622                         CH[i].overload--;           //decrement overload counter
00623                     if(CH[i].overload<ERROR_REP)    //verify overload condition           
00624                         if(CH[i].noload<ERROR_REP)  //verify no load condition
00625                             fail_out(i+1,0);        //Reset failure output      
00626                     
00627                 }
00628                 //Determine no load via software (Resistance over 150 ohm)
00629                 if(CH[i].voltage > 2 && CH[i].current < CH[i].voltage/150)
00630                 {                    
00631                     if(CH[i].noload<=2*ERROR_REP)   //verify counter limit
00632                         CH[i].noload++;             //Increment no load counter 
00633                     if(CH[i].noload>=ERROR_REP)     //Digital Filtering by repetitive no load diagnostics
00634                         fail_out(i+1,1);            //Set failure output
00635                 }
00636                 else
00637                 {
00638                     if(CH[i].noload>0)          
00639                         CH[i].noload--;                 //decrement no load counter
00640                     if(CH[i].noload<ERROR_REP)          //verify no load condition
00641                         if(CH[i].overload<ERROR_REP)    //verify overload condition 
00642                             fail_out(i+1,0);            //Reset failure output 
00643                 }
00644                 
00645                 register_amc = ADC0+i+1;                //Read next ADC (ADC0 to ADC7)
00646                 fast_read_U4();
00647                 
00648                 //Estimate control input (Duty cycle in %)
00649                 CH[i].control = FILTC*CH[i].control+FILTC2*(rx.data*VC_K*5.0/0xFFF+VC_OFF);
00650                 
00651                 #ifndef CAL
00652                     //Verify limits
00653                     if(CH[i].control<0)
00654                         CH[i].control=0;
00655                     if(CH[i].control>100)
00656                         CH[i].control=100;  
00657                 #endif                   
00658             }
00659             DEBUG_PRINTF("Duty Cycle Calibration - Measured Voltage: %f",rx.data*5.0/0xFFF);
00660         } 
00661     }          
00662 }
00663 
00664 //initiate socket instances
00665 void socket_start()
00666 {
00667     server.set_blocking(true); // Set socket connection not blocking
00668     client.set_blocking(false,50);
00669     server.bind(PORT); //  TCP Socket setup
00670     server.listen(2); //  Socket Server start listening request. 
00671 }
00672 
00673 
00674 //Server loop (thread triggered)
00675 void server_loop(void)
00676 {
00677     while(1)
00678     {
00679         httpsvr.run(&CH[0],dev_name);        //wait for new client connection 
00680         server_led = !server_led;   //togle server led    
00681     }
00682 }
00683 
00684 //Socket loop (thread triggered) - for EPICS
00685 void socket_loop(void)
00686 {
00687     
00688     while(1)
00689     {
00690         socket_led = !socket_led;   //toggle socket LED
00691                 
00692         if(server.accept(client)!=-1)   //blocks waiting for a new client
00693         {
00694             client.set_blocking(false,50);  // Set client connection not blocking
00695             while(client.is_connected())    // while connected
00696             {
00697                 socket_led = !socket_led;   //toggle LED again (fast flash)
00698                 receive_return = client.receive_all(socket_buffer,200); //receive all messages
00699                 if(receive_return>0)    //if bytes received
00700                 {
00701                     message_treatment();            //treat message
00702                     client.send_all(send_buffer,n); //send answer
00703                 }
00704                 if(receive_return < 0)              //if erro, break connection
00705                     break;
00706             }
00707             client.close(); //finally close the client
00708         }       
00709     }
00710 }
00711 
00712 //AMC7812B setup (U4 and U5)
00713 void amc_setup(void){
00714     
00715     cs_u4 = 1;      //Chip Select must be deselected
00716     cs_u5 = 1;      //Chip Select must be deselected
00717     dac_clr = 1;    //DAC Clear inactive
00718     amc_reset = 1;  //Reset Inactive
00719     cnvt_u5 = 1;    //U5 Convertion not triggered                     
00720     cnvt_u4 = 1;    //U4 Convertion not triggered
00721     
00722     //Reset AMC7812B to make sure both are in the initial state
00723     amc_reset = 0;
00724     wait_ms(5);
00725     amc_reset = 1;
00726     
00727     // Setup the spi for 12 bit data, high steady state clock,
00728     // second edge capture, with a 10MHz clock rate
00729     spi.format(12,1);
00730     spi.frequency(10000000);
00731     
00732     wait_ms(10);             //Wait AMC7812B power up
00733     
00734     //Disabling Power Down Register
00735     tx.data = 0x7FFE;
00736     register_amc = PWR_DOWN;
00737     write_U4();
00738     write_U5();
00739     
00740     //Set all ADC range 0 to 5V
00741     tx.data = 0xFFFF;
00742     register_amc = ADC_GAIN;
00743     write_U4();
00744     write_U5();
00745 
00746     //Set all u4 16 ADC channels active
00747     register_amc = ADC_CH0;
00748     tx.data = 0x6DFF;
00749     write_U4();
00750     register_amc = ADC_CH1;
00751     tx.data = 0x7000;
00752     write_U4();
00753     
00754     //Set u5 first 8 ADC channels active
00755     tx.data = 0x6DE0;
00756     register_amc = ADC_CH0;
00757     write_U5();
00758     
00759     //Disable LT, D1 and D2
00760     tx.data = 0x0000;
00761     register_amc = T_CONF;
00762     write_U4();
00763     write_U5();
00764     
00765     tx.data = 0x0400; //Set both in direct mode
00766     //tx.data = 0x2400; //Set both in auto mode
00767     register_amc = CONF0;
00768     write_U4();
00769     write_U5();
00770 
00771     tx.data = 0x0300; //Set convertion ate to 62.5kS/s (auto mode)
00772     register_amc = CONF1;
00773     write_U4();
00774     write_U5();
00775     
00776 }
00777 
00778 //Adjust current limit
00779 //
00780 // Parameters:
00781 // - int channel: channel to adjust (from 1 to 8)
00782 // - float value: current value
00783 //
00784 void adj_ilimit(int channel,float value) //channel from 1 to 8
00785 {
00786     if(value > CURR_MAX_LIMIT) //current allowed up to CURR_MAX_LIMIT
00787         value = CURR_MAX_LIMIT;
00788         
00789     value = value*I_K+I_OFF;    //Convert to voltage
00790     
00791     tx.data = int((0xFFF*value)/5)&0xFFF;   //Convert to 12 bit data
00792     register_amc=DAC0+channel-1;            //set register
00793     write_U4();                             //write U4 AMC7812B DAC
00794 }
00795 
00796 //Set/Reset Failure Output
00797 //
00798 // Parameters:
00799 // - int channel: channel to adjust (from 1 to 8)
00800 // - int value: output 5V (value=1) or 0V (value=0)
00801 //
00802 void fail_out(int channel,int value)//channel from 1 to 8
00803 {
00804     tx.data = 0xFFF*value;          //set 12bit data to DAC
00805     register_amc=DAC0+channel-1;    //set register
00806     write_U5();                     //write U5 AMC7812B
00807     CH[channel-1].failure = value;  //update data structure
00808 }
00809 
00810 //U4 end of convertion Interrupt 
00811 void end_conv_u4(void){
00812     flag_end_u4 = 1;        //set U4 flag
00813 }
00814 
00815 //U5 end of convertion Interrupt 
00816 void end_conv_u5(void){
00817     flag_end_u5 = 1;        //set U5 flag
00818 } 
00819 
00820 //Trigger Both (U4 and U5) AD convertions
00821 void trigger_conv(void){
00822     
00823     //Triggering ADC via software - Setting flag ICONV inside CONF register
00824     /*
00825     register_amc = CONF0;
00826     read_U4();
00827     tx.data = rx.data | 0x1000;
00828     write_U4();
00829     
00830     read_U5();
00831     tx.data = rx.data | 0x1000;
00832     write_U5();
00833     */
00834     
00835     //Triggering ADC via hardware - CONV pin active low.
00836     cnvt_u5 = 0;
00837     cnvt_u4 = 0;
00838     
00839     cnvt_u5 = 1;
00840     cnvt_u4 = 1;      
00841      
00842 }
00843 
00844 //Trigger U4 convertion
00845 void trigger_u4(void)
00846 {
00847     cnvt_u4 = 0;
00848     cnvt_u4 = 1;
00849 }
00850 
00851 //Trigger U5 convertion
00852 void trigger_u5(void)
00853 {
00854     cnvt_u5 = 0;
00855     cnvt_u5 = 1;
00856 }
00857 
00858 //U5 Fast Read Function
00859 //fast_read saves always the previous read value in rx.data
00860 //See AMC7812B datasheet for more details
00861 void fast_read_U5(void){
00862         cs_u5 = 0; // Select the device by seting chip select low
00863 
00864         reg_aux = spi.write((register_amc|0x80)<<4);
00865         rx.data = (reg_aux&0xF)<<12;
00866         reg_aux = spi.write(0x000);
00867         rx.data = rx.data|(reg_aux&0xFFF);
00868         
00869         cs_u5 = 1; // Deselect the device by seting chip select low 
00870 }
00871 
00872 //U4 Fast Read Function
00873 //fast_read saves always the previous read value in rx.data
00874 //See AMC7812B datasheet for more details
00875 void fast_read_U4(void){
00876         cs_u4 = 0; // Select the device by seting chip select low
00877 
00878         reg_aux = spi.write((register_amc|0x80)<<4);
00879         rx.data = (reg_aux&0xF)<<12;
00880         reg_aux = spi.write(0x000);
00881         rx.data = rx.data|(reg_aux&0xFFF);
00882                  
00883         cs_u4 = 1; // Deselect the device by seting chip select low 
00884 }
00885 
00886 //U5 SPI read function
00887 //Read two times to assure the second read will save the first read result in rx.data
00888 //Takes about two times the fast_read function
00889 void read_U5(void){
00890         cs_u5 = 0; // Select the device by seting chip select low
00891 
00892         spi.write((register_amc|0x80)<<4);
00893         spi.write(0x000);
00894         cs_u5 = 1; // Deselect the device by seting chip select low
00895         cs_u5 = 0; // Select the device by seting chip select low
00896         reg_aux = spi.write((register_amc|0x80)<<4);
00897         rx.data = (reg_aux&0xF)<<12;
00898         reg_aux = spi.write(0x000);
00899         rx.data = rx.data|(reg_aux&0xFFF);
00900         
00901         cs_u5 = 1; // Deselect the device by seting chip select low 
00902 }
00903 
00904 //U4 SPI read function
00905 //Read two times to assure the second read will save the first read result in rx.data
00906 //Takes about two times the fast_read function
00907 void read_U4(void){
00908         cs_u4 = 0; // Select the device by seting chip select low
00909 
00910         spi.write((register_amc|0x80)<<4);
00911         spi.write(0x000);
00912         cs_u4 = 1; // Deselect the device by seting chip select low
00913         cs_u4 = 0; // Select the device by seting chip select low
00914         reg_aux = spi.write((register_amc|0x80)<<4);
00915         rx.data = (reg_aux&0xF)<<12;
00916         reg_aux = spi.write(0x000);
00917         rx.data = rx.data|(reg_aux&0xFFF);
00918         
00919         cs_u4 = 1; // Deselect the device by seting chip select low 
00920 }
00921 
00922 //U4 SPI write function
00923 void write_U4(void){
00924         
00925         cs_u4 = 0; // Select the device by seting chip select low
00926         reg_aux = register_amc<<4|((tx.data&0xF000)>>12);
00927         spi.write(reg_aux);
00928         spi.write(tx.data&0xFFF);
00929         cs_u4 = 1; // Deselect the device by seting chip select low 
00930 }
00931 
00932 //U5 SPI write function
00933 void write_U5(void){
00934         cs_u5 = 0; // Select the device by seting chip select low
00935         reg_aux = register_amc<<4|((tx.data&0xF000)>>12);
00936         spi.write(reg_aux);
00937         spi.write(tx.data&0xFFF);
00938         cs_u5 = 1; // Deselect the device by seting chip select low 
00939 }
00940 
00941 //Initialize variables and LCD
00942 void setup(){
00943     
00944     //Auxiliary variables    
00945     int aux;
00946     char c;
00947     float tmp_lim;
00948     int tmp_en;
00949     uint8_t gpio_init=0;
00950     
00951     phy_rst = 0;    //reset ethernet Phy
00952     eth_led1 = 0;   //turn off ethernet led 1
00953     eth_led2 = 0;   //turn off ethernet led 2
00954     phy_rst = 1;    //Power on ethernet Phy
00955     
00956     display.baud(19200);
00957     
00958     //Clear all display LEDs
00959     display.putc(0xFE);
00960     display.putc(0x5A);
00961     display.putc(0x00);
00962     display.putc(0x00);
00963     display.putc(0xFE);
00964     display.putc(0x5A);
00965     display.putc(0x01);
00966     display.putc(0x00);
00967     display.putc(0xFE);
00968     display.putc(0x5A);
00969     display.putc(0x02);
00970     display.putc(0x00);
00971        
00972     //Set display contrast
00973     display.putc(0xFE);
00974     display.putc(0x91);
00975     display.putc(0x80);
00976     
00977     //Config file handler
00978     cfg_file = fopen("/local/lim.cfg", "r");  // Open "lim.cfg" on the local file system for reading
00979     if(cfg_file==NULL)  //If config file doesnt exist, create new file
00980     {
00981         cfg_file = fopen("/local/lim.cfg", "w");  //Open "lim.cfg" on the local file system for writing
00982         fprintf(cfg_file,"Channel Configuration - Current Limit and Enable\n");
00983         fprintf(cfg_file,"%s\n",DEVICE_NAME);
00984         strcpy(dev_name,DEVICE_NAME);
00985         for(i=0;i<8;i++)
00986         {
00987             CH[i].limit = DEFAULT_CURR_LIMIT;    //Save default current limit in all channels          
00988             fprintf(cfg_file,"%d %3.2f 1\n",i+1,DEFAULT_CURR_LIMIT);  //Write to file
00989             CH[i].enable = 1;
00990         }
00991         ERROR_PRINTF("lim.cfg file not found! Creating default file...");
00992     }
00993     else                //File exists :)
00994     {
00995         do{
00996             c = getc(cfg_file);
00997         }while(c!='\n');    //Linescan (scan until \n)
00998         fscanf(cfg_file,"%s",dev_name); //Read name string
00999         for(i=0;i<8;i++)    //Read 8 channels
01000         {
01001             fscanf(cfg_file,"%d %f %d",&aux,&tmp_lim,&tmp_en); //Read channel and limit value
01002             if(tmp_lim<0||tmp_lim>CURR_MAX_LIMIT)   //Verify limits
01003                 tmp_lim=DEFAULT_CURR_LIMIT;         //If tmp is above limit, use default  
01004             CH[i].limit = tmp_lim;  //set channel limit
01005             CH[i].enable = tmp_en&0x1;
01006         }   
01007     }
01008     fclose(cfg_file);   //close config file
01009     gpio_init=0;
01010     for(i=0;i<8;i++)    //set structure variables
01011     {
01012         CH[i].noload = 0;   //no load variable
01013         CH[i].overload = 0; //oveload variable     
01014         fail_out(i+1,0);    //reset failure output
01015         adj_ilimit(i+1,CH[i].limit);    //adjust current limit 
01016         gpio_init = gpio_init | (CH[i].enable&0x1)<<i;
01017     }
01018         
01019     write_LCD();        //write to LCD
01020       
01021     reset_config();     //reset configuration
01022     flag_end_u4=0;      //reset U4 end of convertion flag
01023     flag_end_u5=0;      //reset U5 end of convertion flag
01024     
01025     //set GPIO aoutput high (enable)
01026     tx.data = gpio_init;
01027     //enable all channels (hardware GPIO)
01028     register_amc = GPIO;
01029     write_U5();
01030     
01031 }
01032 
01033 //Clear LCD Function
01034 void clear_lcd(){
01035     display.putc(0xFE);
01036     display.putc(0x58);
01037 }
01038 
01039 //Set Red Led - Error
01040 void error(){
01041     display.putc(0xFE);
01042     display.putc(0x5A);
01043     display.putc(0x00);
01044     display.putc(0x02);
01045 }
01046 
01047 //Set Green Led - Normal
01048 void normal(){
01049     display.putc(0xFE);
01050     display.putc(0x5A);
01051     display.putc(0x00);
01052     display.putc(0x01);
01053 }
01054 
01055 //Set Red and Green - Disabled
01056 void disabled(){
01057     display.putc(0xFE);
01058     display.putc(0x5A);
01059     display.putc(0x00);
01060     display.putc(0x03);
01061 }
01062 
01063 //Write channel index to LCD
01064 void write_LCD()
01065 {
01066     if(CH[LCD_index].failure == 1)      
01067         error();                          //error status if failure
01068     else
01069     {
01070         if(CH[LCD_index].enable == 0)
01071             disabled();                   //disabled status if not enabled
01072         else
01073             normal();                     //Normal mode
01074     }
01075     clear_lcd();                          //Clear LCD
01076     display.printf("CH%d %5.2fV/%3.2fAC:%03.0f%%  IL:%3.2fA",LCD_index+1,CH[LCD_index].voltage,CH[LCD_index].current,CH[LCD_index].control,CH[LCD_index].limit);
01077 }
01078 
01079 //Heartbeat toogle MBED led function 
01080 void heart(){
01081     blink = !blink; //toggle blink led
01082 }