Monday, April 29, 2013

Modbus RTU sample frame 8N1.

Recently, I have been working on modbus RTU for communication between ABB ACS800 (a type of motor drive) and dsPIC33FJ128mc. Finally, I made it to work.
However, during development time, I was trying to google for sample Modbus RTU frame, but I could not find a good source. Hence, after making it work, I decided to post it here:
Request frame : 1 3 0 101 0 1 148 21 (in DEC)

Respond frame : 0 1 3 2 52 22 47 74 0 (in DEC)

Wednesday, April 24, 2013

Oracle SET DEFINE OFF

I had a script that contains "&" characters and sqldeveloper constantly prompts me for input.
Solution found from https://forums.oracle.com/forums/thread.jspa?threadID=1032337 is just to simply call "SET DEFINE OFF;" at the beginning of the script.

Monday, April 22, 2013

Hibernate autocommit session + Transaction.

This feature is extremely dangerous If we are not aware of. For example:
Let's say I have a simple service method :
  @Transactional  
   public void addCompany(Company company) {  
       company.setName("Name_1");
       companyDAO.saveOrUpdate(company); 
       company.setName("Name_2");
   }  

companyDAO is using HibernateSupport to manage entities.
What do we expect the name of our company in the DB looks like ?
At first glimpse, one might just state : "Name_1" because we actually did not call DAO to save our entity.
However, that's might not be the case if autocommit feature of Hibernate session is ON (I think it is ON by default). Therefore:
companyDAO.saveOrUpdate(company); will attach company entity to current Hibernate session. And when transaction ends, Hibernate will try to commit session. As the result, name of target entity in DB is actually "Name_2". Suprise(or not) :) ! Transaction gives us great power, but great power comes great responsibility ;)

Thursday, April 11, 2013

Vaadin < 7.0.3 + TreeTable(or Table) + Context Menu ( Action Handler ) refreshing problem

Today, I had a tedious problem with Vaadin TreeTable's context menu. In addition, I do think that Table has similar problem as well.
Here is what I do :
1. Do addActionHandler(new Action.Handler() { ...}) to TreeTable.
2. After that, there is a button click event that triggers : removeAllActionHandlers();from TreeTable.
3. Lastly, I add new ActionHandler to TreeTable : addActionHandler(new Action.Handler() { ...})
I expected that context menus from Action.Handler created in step 3 will replace those context menus from step 1. However, that's not the case, context menu did not get updated/refreshed.
Although one ticket was submitted and marked as fixed in Vaadin's bug tracker : . It seems that I still need to force a refresh with refreshRowCache() to refresh context menu. However, refreshRowCache() has problems with generated columns of TreeTable that I can't use it. Moreover, refreshRowCache() is not such a good function to use according to Vaadin's document: "Note that calling this method is not cheap so avoid calling it unnecessarily" So I had a deeper look at the code :
  /**  
    * Removes all action handlers  
    */  
   public void removeAllActionHandlers() {  
     actionHandlers = null;  
     actionMapper = null;  
     // Assures the visual refresh. No need to reset the page buffer  
     // before as the content has not changed, only the action  
     // handlers.  
     refreshRenderedCells();  
   }  
The key problem lies in refreshRenderedCells function
  protected void refreshRenderedCells() {  
     ...  
     if (!isContentRefreshesEnabled) {  
       return;  
     }  
           ...  
  }  
Then I noticed isContentRefreshesEnabled is false. As a result, context menu was not updated properly:
  protected void enableContentRefreshing(boolean refreshContent) {  
     isContentRefreshesEnabled = true;  
     if (refreshContent) {  
       refreshRenderedCells();  
       // Ensure that client gets a response  
       markAsDirty();  
     }  
   }  
Voila, instead of calling refreshRowCache(), enableContentRefreshing(true) should be called to update the context menu.
1. Do addActionHandler(new Action.Handler() { ...}) to TreeTable.
2. After that, there is a button click event that trigger : removeAllActionHandlers();from TreeTable.
3. Add new ActionHandler to TreeTable : addActionHandler(new Action.Handler() { ...})
4. Call enableContentRefreshing(true)


I am not entirely sure if this is a bug, but at least it is my work-around for this problem.

Wednesday, April 10, 2013

ADIS16209 sensor & dspiC33FJ128MC802 & SPI

The task is my first hands-on experience with PIC programming(dspic33FJ). In my opinion, dspiC33FJ128MC802 is a powerful and flexible PIC since it has re-mappable I/Os. This particular feature has also imposed some difficulties for a PIC newbie like me.
So, here is the task : make ADIS16209 sensor work with dspiC33FJ128MC802 via SPI.
Connections:
PIN 6 <---> MOSI (Master out slave in)
PIN 7 <---> MISO (Master in slave out)
PIN 22 <---> CS (Chip select)
PIN 11 <---> CLK (Clock)

Biggest problem I have faced was setting correct clock edge and clock polarity for SPI.(I needed an oscilloscope to debug this)
Sample code that works :
 /*  
  * File:  main.c  
  *  
  * Created on February 9, 2010, 10:53 AM  
  */  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <p33Fxxxx.h>  
 _FOSCSEL(FNOSC_FRC);  
 _FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT);  
 _FWDT(FWDTEN_OFF);  
 _FICD(JTAGEN_OFF & ICS_PGD3);  
 short temp;  
 /*  
  *  
  */  
 void delay(void) {  
   long i = 5242;  
   while (i--)  
     ;  
 }  
 void Init_SPI(void) {  
   SPI1STATbits.SPIEN = 0; //Disable SPI1  
   _SPI1IE = 1;  
   _SPI1IF = 0;  
   //*******  
   SPI1CON1bits.MSTEN = 1;  
   SPI1CON1bits.MODE16 = 1;  
   SPI1CON1bits.PPRE = 0;  
   SPI1CON1bits.SPRE = 2;  
   SPI1CON1bits.CKE = 0;  
   SPI1CON1bits.CKP = 1;  
   SPI1CON1bits.SMP=0;  
   SPI1STATbits.SPIEN = 1;  
   _SPI1IF = 0;  
 }  
 void turnLEDDebugOFF() {  
   LATAbits.LATA0 = 0;  
 }  
 void __attribute__((__interrupt__, __auto_psv__)) _SPI1Interrupt(void) {  
   SPI1STATbits.SPIROV = 0;  
   temp = SPI1BUF;  
   temp&=0b0011111111111111; //mask out   
   _SPI1IF = 0;  
    LATBbits.LATB11 = 1; // raise the slave select line}  
 }  
 void write_SPI(short command) {  
   LATBbits.LATB11 = 0; // lower the slave select line  
   // temp = SPI1BUF; // dummy read of the SPI1BUF register to clear the SPIRBF flag  
   SPI1BUF = (command); // write the data out to the SPI peripheral  
  //  while (!SPI1STATbits.SPITBF);     // wait for the data to be sent out  
 //            
  // while (SPI1STATbits.SPIRBF);     // wait for the data to be sent out  
 //  
 }  
 int main(int argc, char** argv) {  
   RCONbits.SWDTEN = 0; /* Disable Watch Dog Timer*/  
   // Configure Oscillator to operate the device at 40Mhz  
   // Fosc= Fin*M/(N1*N2), Fcy=Fosc/2  
   PLLFBD = 38; // M=154  
   CLKDIVbits.PLLPOST = 0; // N2=2  
   CLKDIVbits.PLLPRE = 0; // N1=10  
   OSCTUN = 0; // Tune the FRC  
   // Clock switching to incorporate PLL  
   __builtin_write_OSCCONH(0x01); // Initiate Clock Switch to Internal  
   // FRC with PLL (NOSC=0b001)  
   __builtin_write_OSCCONL(0x01); // Start clock switching  
   while (OSCCONbits.COSC != 0b001); // Wait for Clock switch to occur  
   AD1PCFGL = 0xFFFF; // Pins to digital  
   LATAbits.LATA0 = 1;  
   TRISAbits.TRISA0 = 0;  
   TRISBbits.TRISB12 = 0; //output RB12  
   LATBbits.LATB12=0;  
   LATBbits.LATB12=1;  
   TRISBbits.TRISB3 = 1; //input RB3  
   RPINR20bits.SDI1R = 3; //SDI1 input is associated to pin RP3 (pin 7 of the dsPIC)  
   RPOR2bits.RP4R = 8; //remappable pin RP4 (pin 11 of the dsPIC) is associated to SCK1  
   RPOR1bits.RP2R = 7; //remappable pin RP2 (pin 6 of the dsPIC) is associated to SDO1  
  // RPOR5bits.RP11R = 9; //CS RP11  
   Init_SPI();  
   TRISBbits.TRISB3 = 1; //input RB3  
   TRISBbits.TRISB2 = 0; //output RB2  
   TRISBbits.TRISB4 = 0; //output RB4  
   TRISBbits.TRISB11 = 0; //output RB11  
   LATBbits.LATB11 = 1;  
   while (OSCCONbits.LOCK != 1) {  
   };  
   while (1) {  
     int i = 0;  
     for (i = 0; i < 255; i++) {  
       write_SPI(0x4A00); //read product identification  
       delay();  
     }  
   }  
   return (EXIT_SUCCESS);  
 }