Nico Bollen / LIN

Dependents:   MBED_LIN_RGB_Master_Example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LinMaster.cpp Source File

LinMaster.cpp

00001 /* 
00002  * Master device LIN communication library for mbed
00003  *
00004  * Copyright (C) 2015 Bollen Nico
00005  * 
00006  * Released under GPL v2
00007  *
00008  * Other licensing models might apply at the sole discretion of the copyright holders.
00009  *
00010  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00011  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00012  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00013  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00014  * furnished to do so, subject to the following conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be included in all copies or
00017  * substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00020  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00021  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00022  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00024  */
00025  
00026 #include "LinMaster.h"
00027 
00028 const uint8_t breakPeriodMessage = 40;                      /* number of timer overflows in the break field during normal LIN messages */
00029 const uint8_t breakPeriodAcfg = 74;                         /* number of timer overflows in the break field during autoconfig messages */
00030 
00031 LinMaster::LinMaster(PinName InPin, PinName OutPin) : LinOutPin(OutPin), LinInPin(InPin, PullUp)
00032 {
00033     this->DriverState = INIT;
00034     this->LastError = NoError;
00035     
00036     this->LinOutPin.write(1);
00037 
00038     this->LinInPin.disable_irq();
00039     this->LinInPin.fall(NULL);
00040     
00041     this->DriverState = IDLE;
00042     
00043     (void)this->baudrate(9600);
00044 }
00045 
00046 LinMaster::~LinMaster()
00047 {
00048     this->LinInPin.disable_irq();
00049     this->LinInPin.fall(NULL);
00050     this->HalfbitTicker.detach(); 
00051     this->TimeoutTicker.detach();
00052 }
00053 
00054 bool LinMaster::init(void)
00055 {
00056     this->LinOutPin.write(1);
00057 
00058     this->LinInPin.enable_irq();
00059     this->LinInPin.fall(NULL);
00060 
00061     this->DriverState = IDLE;
00062 
00063     return ( true );
00064 }
00065 
00066 bool LinMaster::baudrate(uint16_t uBaud)
00067 {
00068     bool blReturn = false;
00069 
00070     if ((uBaud > 0) && (uBaud <= 20000))
00071     {
00072         this->u16HalfBitPeriod = std::chrono::microseconds(1000000 / ( 2 * uBaud));
00073         blReturn = true;
00074     }
00075 
00076     return ( blReturn );
00077 }
00078 
00079 uint16_t LinMaster::baudrate(void)
00080 {
00081     return ( 1000000 / (2 * this->u16HalfBitPeriod.count()) );
00082 }
00083 
00084 bool LinMaster::send_frame(Frame_t * ptrFrame)
00085 {
00086     bool blReturn = false;
00087 
00088     if ( (this->DriverState == IDLE) && (this->LinInPin.read() == 1) )
00089     {
00090         /* Clear and initialize all registers */
00091         memset(this->RXbuf, 0, 11);
00092 
00093         /* Disable ticker interrupt */
00094         this->HalfbitTicker.detach();
00095         this->TimeoutTicker.detach();
00096 
00097         this->LinInPin.fall(NULL);
00098 
00099         this->LinOutPin.write(1);
00100 
00101         this->DriverState = TRANSMIT;                       /* State of the LIN bus is transceiving a frame */
00102         this->LastError = NoError;
00103         this->FrameStatus = FStart;
00104         this->ByteStatus = BStart;
00105         this->RXbufIndex = 0;                               /* Reset index in the receiver buffer */
00106         this->TXbufIndex = 0;                               /* Reset index in the transmit buffer */
00107 
00108         /* Set the correct brake-length */
00109         if (ptrFrame->Brake == AutoConfig)
00110         {
00111             this->breakLength = breakPeriodAcfg;
00112         }
00113         else
00114         {
00115             this->breakLength = breakPeriodMessage;
00116         }
00117 
00118         this->FrameLength = 1 + 1 + ptrFrame->DataLen + 1;  /* Frame length = Sync + Frame ID + Data Len + CRC */
00119         this->linMessageType = ptrFrame->FrameType;
00120 
00121         /* Create the correct frame buffer */
00122         this->TXbuf[0] = 0x55;                              /* Sync field */
00123         this->TXbuf[1] = this->parity(ptrFrame->FrameID);   /* Frame ID */
00124 
00125         if (this->linMessageType == M2S)
00126         {
00127             uint16_t u16Crc;
00128             uint8_t i;
00129 
00130             if (ptrFrame->CrcType == Enhanced)
00131             {
00132                 u16Crc = TXbuf[1];
00133             }
00134             else
00135             {
00136                 u16Crc = 0;
00137             }
00138 
00139             for (i = 0; i < ptrFrame->DataLen; i++)
00140             {
00141                 this->TXbuf[i + 2] = ptrFrame->Data[i];     /* Data */
00142                 u16Crc += ptrFrame->Data[i];
00143                 if (u16Crc >= 256)
00144                 {
00145                     u16Crc -= 255;
00146                 }
00147             }
00148             this->TXbuf[ptrFrame->DataLen + 2] = (uint8_t)(~u16Crc);
00149         }
00150         else
00151         {
00152             /* S2M message */
00153 
00154             /* Calculate RX timeout */
00155             this->FrameTimeout = std::chrono::microseconds(((ptrFrame->DataLen + 1) * 14) * 2 * this->u16HalfBitPeriod);
00156         }
00157 
00158         /* Configure and start the half bit timer */
00159         this->HalfbitTicker.attach(callback(this, &LinMaster::TickEventHndl), this->u16HalfBitPeriod);
00160 
00161         blReturn = true;
00162     }
00163     
00164     return ( blReturn );
00165 }
00166 
00167 bool LinMaster::get_rx_data(Frame_t &ptrFrame)
00168 {
00169     uint16_t u16Crc;
00170     uint8_t i;
00171 
00172     if ( (this->DriverState != IDLE) || (this->LastError != NoError))
00173     {
00174         return (false);
00175     }
00176 
00177     /* Copy data and check RX frame CRC */
00178     if (ptrFrame.CrcType == Enhanced)
00179     {
00180         u16Crc = RXbuf[1];
00181     }
00182     else
00183     {
00184         u16Crc = 0;
00185     }
00186 
00187     for (i = 0; i < ptrFrame.DataLen; i++)
00188     {
00189         ptrFrame.Data[i] = RXbuf[1 + 1 + i];
00190         u16Crc += RXbuf[1 + 1 + i];
00191         if (u16Crc >= 256)
00192         {
00193             u16Crc -= 255;
00194         }
00195     }
00196     
00197     if (this->RXbuf[ptrFrame.DataLen + 2] == (uint8_t)(~u16Crc))
00198     {
00199         return (true);
00200     }
00201     else
00202     {
00203         return (false);
00204     }
00205 }
00206 
00207 void LinMaster::TickEventHndl(void)
00208 {
00209     int PinLevel = this->LinInPin.read();
00210 
00211     if (this->FrameStatus < Break_OK)
00212     {
00213         /* Do break field transmission */
00214         if (this->breakLength > 2)
00215         {
00216             /* Dominant Level */
00217             this->LinOutPin.write(0); 
00218         }
00219         else
00220         {
00221             /* Recessive Level */
00222             this->LinOutPin.write(1); 
00223         }
00224 
00225         if (this->breakLength > 0)
00226         {
00227             this->breakLength--;
00228         }
00229         else
00230         {
00231             this->FrameStatus = Break_OK;
00232         }
00233     }
00234     else
00235     {
00236         /* Break field was transmitted */
00237         if (this->FrameLength == 0)
00238         {
00239             /* No data needs to be transmitted */
00240             
00241             /* Disable ticker interrupt */
00242             this->HalfbitTicker.detach();
00243             this->TimeoutTicker.detach();
00244             
00245             /* Disable LIN bus level interrupt */
00246             this->LinInPin.fall(NULL);
00247         }
00248         else
00249         {
00250             /* Data needs to be transmitted or received */
00251             if ( (this->linMessageType == S2M) &&
00252                  (this->FrameStatus >= ID_OK))
00253             {
00254                 if (this->ByteStatus > BStart)
00255                 {
00256                     /* Not waiting for start bit */
00257                     this->ByteStatus = static_cast<ByteStatus_t>(static_cast<int>(this->ByteStatus)+1);
00258                 }
00259 
00260                 /* S2M message data receiving */
00261                 switch (this->ByteStatus)
00262                 {
00263                 case StartbitSample:
00264                     if (PinLevel == 0)
00265                     {
00266                         /* OK */
00267                     }
00268                     else
00269                     {
00270                         /* TODO error */
00271                     }
00272 
00273                     break;
00274 
00275                 case Databit0Sample:
00276                 case Databit1Sample:
00277                 case Databit2Sample:
00278                 case Databit3Sample:
00279                 case Databit4Sample:
00280                 case Databit5Sample:
00281                 case Databit6Sample:
00282                 case Databit7Sample:
00283                     /* Mid of single bit time, do sampling */
00284                     this->RXbuf[RXbufIndex] >>= 1;
00285                     this->RXbuf[RXbufIndex] |= (PinLevel << 7);
00286                     break;
00287 
00288                 case StopbitSample:
00289                     /* End of stop bit, stop Timer IRQ */
00290 
00291                     /* Enable LIN bus level interrupt */
00292                     this->LinInPin.fall(callback(this, &LinMaster::PinEventHndl));
00293 
00294                     /* Disable half bit interrupt */
00295                     this->HalfbitTicker.detach();
00296 
00297                     /* Check the current bus level */
00298                     if (PinLevel == 0)
00299                     {
00300                         this->LastError = FramingErr;       /* stop bit not valid => framing error */
00301                     }
00302 
00303                     this->RXbufIndex++;
00304                     this->FrameStatus = static_cast<FrameStatus_t>(static_cast<int>(this->FrameStatus)+1);
00305                     this->ByteStatus = BStart;
00306 
00307                     if ((this->RXbufIndex >= this->FrameLength) ||
00308                         (this->LastError != NoError))
00309                     {
00310                         /* All requested data bytes are received or an error occurred */
00311                         this->DriverState = IDLE;
00312                         
00313                         /* Disable LIN bus level interrupt */
00314                         this->LinInPin.fall(NULL);
00315 
00316                         /* Disable timeout ticker */
00317                         this->TimeoutTicker.detach();
00318                     }
00319                     else
00320                     {
00321                         /* Wait for a new data byte */
00322                     }
00323                     break;
00324                     
00325                 case Databit0Edge:
00326                 case Databit1Edge:
00327                 case Databit2Edge:
00328                 case Databit3Edge:
00329                 case Databit4Edge:
00330                 case Databit5Edge:
00331                 case Databit6Edge:
00332                 case Databit7Edge:
00333                 case StopbitEdge:
00334                 case BDone:
00335                 case BStart:
00336                 default:
00337                     /* Do nothing */
00338                     break;
00339                 }
00340             }
00341             else
00342             {
00343                 /* Transmission of Sync + Frame ID and M2S frame data */
00344                 this->ByteStatus = static_cast<ByteStatus_t>(static_cast<int>(this->ByteStatus)+1);
00345 
00346                 switch (this->ByteStatus)
00347                 {
00348                 case StartbitEdge:
00349                     /* Start bit : start */
00350                     this->LinOutPin.write(0); 
00351                     break;
00352 
00353                 case StartbitSample:
00354                     /* Start bit : mid */
00355                     break;
00356 
00357                 case Databit0Edge:
00358                 case Databit1Edge:
00359                 case Databit2Edge:
00360                 case Databit3Edge:
00361                 case Databit4Edge:
00362                 case Databit5Edge:
00363                 case Databit6Edge:
00364                 case Databit7Edge:
00365                     /* Start of new bit time */
00366                     if (this->TXbuf[this->TXbufIndex] & 0x01)
00367                     {
00368                         /* Recessive Level */
00369                         this->LinOutPin.write(1); 
00370                     }
00371                     else
00372                     {
00373                         /* Dominant Level */
00374                         this->LinOutPin.write(0); 
00375                     }
00376 
00377                     this->TXbuf[this->TXbufIndex] >>= 1;
00378                     break;
00379 
00380                 case Databit0Sample:
00381                 case Databit1Sample:
00382                 case Databit2Sample:
00383                 case Databit3Sample:
00384                 case Databit4Sample:
00385                 case Databit5Sample:
00386                 case Databit6Sample:
00387                 case Databit7Sample:
00388                     /* Odd overflow, mid of bit time ==> sample the bus for RX */
00389                     this->RXbuf[this->RXbufIndex] >>= 1;
00390                     this->RXbuf[this->RXbufIndex] |= ((PinLevel << 7) & 0x80);
00391                     break;
00392 
00393                 case StopbitEdge:
00394                     /* Stop bit : start */
00395                     this->LinOutPin.write(1); 
00396                     break;
00397 
00398                 case StopbitSample:
00399                     /* Stop bit : mid / level check */
00400                     if (PinLevel == 0)
00401                     {
00402                         /* Stop bit not valid => framing error */
00403                         this->LastError = FramingErr;
00404                         this->DriverState = IDLE;
00405 
00406                         /* Disable ticker interrupt */
00407                         this->HalfbitTicker.detach();
00408                         this->TimeoutTicker.detach();
00409 
00410                         /* Disable LIN bus level interrupt */
00411                         this->LinInPin.fall(NULL);
00412                     }
00413 
00414                     this->FrameStatus = static_cast<FrameStatus_t>(static_cast<int>(this->FrameStatus)+1);
00415                     this->TXbufIndex++;
00416                     this->RXbufIndex++;
00417 
00418                     if ((this->linMessageType == S2M) && (this->FrameStatus == ID_OK))
00419                     {
00420                         /* Stop bit of header is sent, now start receiving data bytes */
00421 
00422                         /* Enable LIN bus level interrupt */
00423                         this->LinInPin.fall(callback(this, &LinMaster::PinEventHndl));
00424 
00425                         /* Disable half bit interrupt */
00426                         this->HalfbitTicker.detach();
00427 
00428                         /* Enable frame timeout interrupt */
00429                         this->TimeoutTicker.attach(callback(this, &LinMaster::RXtimeoutEventHndl), this->FrameTimeout);
00430                     }
00431                     break;
00432 
00433                 case BDone:
00434                     /* Stop bit : finished */
00435                     this->ByteStatus = BStart;
00436 
00437                     if (this->TXbufIndex >= this->FrameLength)
00438                     {
00439                         /* M2S frame, Last byte is sent */
00440                         this->LastError = NoError;
00441                         this->DriverState = IDLE;
00442 
00443                         /* Disable LIN bus level interrupt */
00444                         this->LinInPin.fall(NULL);
00445 
00446                         /* Disable ticker interrupts */
00447                         this->TimeoutTicker.detach();
00448                         this->HalfbitTicker.detach();
00449                     }
00450                     break;
00451 
00452                 default:
00453                     break;
00454                 }
00455             }
00456         }
00457     }
00458 }
00459 
00460 void LinMaster::RXtimeoutEventHndl(void)
00461 {
00462     /* Disable LIN bus level interrupt */
00463     this->LinInPin.fall(NULL);
00464 
00465     /* Disable half bit interrupt */
00466     this->HalfbitTicker.detach();
00467     this->TimeoutTicker.detach();
00468 
00469     this->DriverState = IDLE;
00470     this->LastError = NoSlaveResp;
00471 }
00472 
00473 void LinMaster::PinEventHndl(void)
00474 {
00475     switch (this->DriverState)
00476     {
00477     case TRANSMIT:
00478     case RECEIVE:
00479     {
00480         this->ByteStatus = StartbitSample;                  /* Set status of the received byte */
00481 
00482         /* Reset ticker */
00483         this->HalfbitTicker.attach(callback(this, &LinMaster::TickEventHndl), this->u16HalfBitPeriod);
00484 
00485         /* Disable LIN bus level interrupt */
00486         this->LinInPin.fall(NULL);
00487         break;
00488     }
00489 
00490     case IDLE:
00491     case DOMINANT:
00492     case TXWAKEUP:
00493         break;
00494 
00495     case RXWAKEUP:
00496     default:
00497         this->DriverState = RXWAKEUP;                       /* It's a wake up pulse */
00498         break;
00499     }
00500 }
00501 
00502 /** Calculate the parity bits
00503  *
00504  * @param u8BYTE original byte
00505  * @return BYTE including parity bits
00506  */
00507 uint8_t LinMaster::parity(uint8_t u8BYTE)
00508 {
00509     uint8_t P0 = 0;
00510     uint8_t P1 = 0;
00511 
00512     /* P0 = ID0 + ID1 + ID2 + ID4
00513      * P1 = ~(ID1 + ID3 + ID4 + ID5)
00514      */
00515     if ((u8BYTE & (1 << 0)) != 0)
00516     {
00517         P0 = ~P0;
00518     }
00519 
00520     if ((u8BYTE & (1 << 1)) != 0)
00521     {
00522         P0 = ~P0;
00523     }
00524 
00525     if ((u8BYTE & (1 << 2)) != 0)
00526     {
00527         P0 = ~P0;
00528     }
00529 
00530     if ((u8BYTE & (1 << 4)) != 0)
00531     {
00532         P0 = ~P0;
00533     }
00534 
00535     if ((u8BYTE & (1 << 1)) != 0)
00536     {
00537         P1 = ~P1;
00538     }
00539 
00540     if ((u8BYTE & (1 << 3)) != 0)
00541     {
00542         P1 = ~P1;
00543     }
00544 
00545     if ((u8BYTE & (1 << 4)) != 0)
00546     {
00547         P1 = ~P1;
00548     }
00549 
00550     if ((u8BYTE & (1 << 5)) != 0)
00551     {
00552         P1 = ~P1;
00553     }
00554 
00555     P1 = ~P1;
00556 
00557     u8BYTE &= 0x3f;                                         /* Delete MSB's */
00558 
00559     if (P0 != 0)
00560     {
00561         u8BYTE |= (1 << 6);
00562     }
00563 
00564     if (P1 != 0)
00565     {
00566         u8BYTE |= (1 << 7);
00567     }
00568 
00569     return (u8BYTE);
00570 }
00571 
00572 /* EOF */