www.pudn.com > Net_apps.rar > splc.c


/* 
********************************************************************************************************* 
* Copyright 2005 Rico Technology CO., LTD. ALL RIGHTS RESERVED. 
* This software is provided under license and contains proprietary and 
* confidential material which is the property of Rico tech. 
* 
* FileName     : 
* Description  : search PLC modem 
* 
* 
* Version control: 
*  $Revision: 0.1 $    Date: 2005/11/14 11:16:00 By jgy 
*      first implemetation 
* 
********************************************************************************************************* 
*/ 
 
#include "..\include\L2\system\low_netif.h" 
#include "..\include\L2\system\sq_mac.h" 
#include "..\include\L1\lwip\netif.h" 
#include "..\include\L1\lwip\pbuf.h" 
#include "..\include\L2\system\plc.h" 
#include "..\include\L3\net_apps\IoEnv.h" 
#include "..\include\L2\system\gpio.h" 
 
#if SEARCH_PLC 
#define kIntellonMacType 0x887b 
#define Swap2Bytes(s) ((((s) >> 8) & 0xff) | (((s) & 0xff) << 8)) 
#define RESET_NET  6   //PIO6 
#define PCA_cMaxRxBuffers  8 
 
static BOOLEAN findLocals(void); 
static BOOLEAN findViperLocals(void); 
static BOOLEAN findHPLocals(void); 
static BOOLEAN readAndFlip(INT32U timeout, INT8U *pRsp); 
static void isEEPROMValid(void); 
static BOOLEAN sendLocalParam(MACAddress SA, MACAddress DA, INT8U CTRL); 
static BOOLEAN sendNetStatsMME(MACAddress SA, MACAddress DA); 
static void sendPrivateMME(MACAddress DA, char mid, char *dataPtr, INT8U dataLen); 
static void readDeviceDescriptionResponse(Private_MME *mmePtr); 
static BOOLEAN PCA_bWrite(void *, INT16U PktLen); 
static BOOLEAN sameMacAddress(MACAddress macAddr1, MACAddress macAddr2); 
static BOOLEAN receiveFrame(INT8U *p, int *dataLen); 
static struct ReceivePackage_t* rx(void); 
static void viperRequestDeviceDescription(void); 
static BOOLEAN viperReadResponse(char* message); 
static BOOLEAN viperIsLocal(void); 
static BOOLEAN viperWaitForResponse(char *DATA); 
static BOOLEAN requestNetStats(void); 
static BOOLEAN viperRequestNetStats(void); 
static void viperRequestMACVersion(void); 
static struct pbuf *rico_low_level_input(struct netif *); 
 
static MACAddress  gBroadcastAddress = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 
static MACAddress  gNICAddress; 
static BOOLEAN  gResponseIn; 
static BOOLEAN  gLocalMACSet; 
static BOOLEAN  gLocalIsViper; 
static INT8U gGlobalRetry;      //Global Retry Counter 
static struct ReceivePackage_t huge gRX[PCA_cMaxRxBuffers]; 
 
/* Local Device */ 
static struct localDev_t localDev; 
 
OS_EVENT    *searchPLCMbox;   //add by jgy for searching PLC modem 05/11/28 
 
void searchPLC_thread(void *data) 
{ 
   BOOLEAN allok; 
   INT8U err; 
 
   searchPLCMbox = OSMboxCreate((void*)0); 
   for(;;) 
   { 
      OSMboxPend(searchPLCMbox, 0, &err); 
      allok = findLocals(); 
      if(!allok) 
      {//local device is dead, so reset 
         GPIO_OUT(RESET_NET); 
         GPIO_BIT_CLR(RESET_NET); 
         OSTimeDlyHMSM(0, 0, 0, 10); 
         GPIO_BIT_SET(RESET_NET); 
         GPIO_IN(RESET_NET); 
      } 
   } 
} 
 
// searches for all the local devices, either viper or HP 1.0 
BOOLEAN findLocals() 
{ 
    BOOLEAN anyFound, viperFound; 
    int i; 
 
    gLocalIsViper = FALSE; 
    memset(&localDev, 0, sizeof(localDev)); 
    memcpy(gNICAddress, netif_list->hwaddr, kAddrSize); 
    for(i = 0; i < PCA_cMaxRxBuffers; i++) 
       gRX[i].status = STATUS_PENDING; 
 
    //look for HP1.0 local devices on 8201 
    anyFound = findHPLocals(); 
 
    //now look for any vipers on any other NICs or if no HP1.0 on a single NIC 
    viperFound = findViperLocals(); 
    if(viperFound) 
        anyFound = TRUE; 
    return anyFound; 
} 
 
BOOLEAN findViperLocals() 
{ 
    BOOLEAN found = FALSE; 
    BOOLEAN anyFound = FALSE; 
 
    found = viperIsLocal(); 
    if(found) 
    { 
        anyFound = TRUE; 
        viperRequestMACVersion(); 
        viperWaitForResponse(NULL); 
        localDev.EEPROMValid = TRUE; 
        localDev.Present = TRUE; 
        localDev.Type = kDeviceIsViper; 
    } 
    return anyFound; 
} 
 
BOOLEAN findHPLocals() 
{ 
    INT8U retries; 
    INT8U pRsp[1514]; 
    BOOLEAN  found = FALSE; 
 
    gGlobalRetry = 0; 
    gLocalIsViper = FALSE; 
    for(retries = 0; retries < 3; retries++) 
    { 
        //send the stats request out.. 
        requestNetStats(); 
 
        //wait for a response 
        if(readAndFlip(50+(retries*100), pRsp)) 
        { 
           gGlobalRetry = 0; 
           break; 
        } 
    } 
    if(retries == 3 && gGlobalRetry == 3) 
    { 
        gGlobalRetry = 0; 
        localDev.Present = FALSE; 
    } 
    else 
       gGlobalRetry++; 
 
    if(localDev.Present) 
       found = TRUE; 
 
    return found; 
} 
 
//sends Request Network Stats.PRIVATE to 5200 and earlier HP 
BOOLEAN requestNetStats() 
{ 
    BOOLEAN result = FALSE; 
    MACAddress SA, DA; 
 
    //send 5200, 51x1 private MME 
    memcpy(DA, gBroadcastAddress, kAddrSize); 
    memcpy(SA, netif_list->hwaddr, kAddrSize); 
    result = sendNetStatsMME(SA, DA); 
 
    return result; 
} 
 
/*************************************** 
sends Request Network Stats MME. 
Return Value: 
TRUE = success, FALSE = error occured 
***************************************/ 
BOOLEAN sendNetStatsMME(MACAddress SA, MACAddress DA) 
{ 
    RSP_Frame_t buffer; 
    RSP_Frame_t *pIf = &buffer; 
 
    if(gLocalIsViper) 
    { 
       viperRequestNetStats(); 
       return 1; 
    } 
    //clear the buffer miniumum 
    memset(pIf, 0, sizeof(REQ_Frame_t)); 
    memcpy(pIf->DA, DA, kAddrSize); 
    memcpy(pIf->SA, SA, kAddrSize); 
    pIf->Ethertype = API_cIntellonMacType; 
    pIf->MCTRL = 0x01;    //1 Mac Management entry 
    pIf->MEHDR = API_cReqNetStats; 
    pIf->MELEN = API_cReqNetStatsSize; 
    pIf->DATA[0] = EK_cReturnNetStats;    //ask for report, 0 would clear chip 
    //send the frame out 
    return PCA_bWrite(pIf, sizeof(buffer)); 
} 
 
//send a packet, returns true if successful 
BOOLEAN PCA_bWrite(void *pIf, INT16U packetLen) 
{ 
   BOOLEAN bReturnStatus = FALSE; 
 
   if(packetLen > PCA_cMaxFrameLength) 
      return bReturnStatus; 
   if(packetLen < PCA_cMinFrameLength) 
      packetLen += PCA_cMinFrameLength - packetLen; 
   //send the packet 
   DRIVER_send_pack(pIf, packetLen); 
   bReturnStatus = TRUE;              //always return true 
 
   return bReturnStatus; 
} 
 
BOOLEAN readAndFlip(INT32U timeout, INT8U *pRsp) 
{ 
    BOOLEAN flipComplete; 
    INT32U t1; 
    struct ReceivePackage_t *ppktbuf; 
 
    flipComplete = FALSE; 
    t1 = OSTimeGet() + OS_TICKS_PER_SEC * (timeout + 500L / OS_TICKS_PER_SEC) / 1000L;   //unit:ms 
    while(1) 
    { 
        if((OSTimeGet() >= t1)||(flipComplete)) 
           break; 
        gResponseIn = FALSE; 
        ppktbuf = rx();      //接收帧,重要 
        //see if we have to fix the bridge 
        if(gResponseIn) 
        { 
           gResponseIn = FALSE; 
           flipComplete= TRUE; 
        } 
        if(ppktbuf != NULL) 
        {//copy the packet 
           memcpy(pRsp, ppktbuf->PacketBuffer , ppktbuf->nBytesReturned); 
        } 
        OSTimeDly(1); 
    } 
    return flipComplete; 
} 
 
//callback function. called by ethernetif_input() 
void PLC_input(struct pbuf *pbuf) 
{//copy response frame of plc modem to buffer 
   int i; 
 
   for(i = 0; i < PCA_cMaxRxBuffers; i++) 
   { 
      if(gRX[i].status == STATUS_PENDING) 
      { 
         gRX[i].status = STATUS_SUCCESS; 
         gRX[i].nBytesReturned = pbuf->len; 
         memcpy(gRX[i].PacketBuffer, (char*)pbuf->payload, pbuf->len); 
         return; 
      } 
   } 
} 
 
struct ReceivePackage_t* PCA_bRead() 
{ 
   int i; 
 
   for(i = 0; i < PCA_cMaxRxBuffers; i++) 
   { 
      if(gRX[i].status == STATUS_SUCCESS) 
      { 
          gRX[i].status = STATUS_PENDING; 
          //return the packet to the caller 
          return &gRX[i]; 
      } 
   } 
   return NULL; 
} 
 
struct ReceivePackage_t* rx(void) 
{ 
    RSP_NET_Frame_t *pRsp; 
    SLP_FrameRsp_t *pEEPROM_Rsp; 
    struct ReceivePackage_t *ppktbuf; 
 
    //read a frame 
    ppktbuf = PCA_bRead(); 
    if(ppktbuf != NULL) 
    { 
       pRsp = (RSP_NET_Frame_t*)ppktbuf->PacketBuffer; 
       if(pRsp->Ethertype == API_cIntellonMacType)   ///* Check for Intellon EtherType */ 
       {//see if we got something from our local node, if so we need to flip 
           //if(sameMacAddress(pRsp->DA, pRsp->SA) && !sameMacAddress(pRsp->DA, gBroadcastAddress)) 
           if(sameMacAddress(pRsp->DA, gNICAddress) && !sameMacAddress(pRsp->DA, gBroadcastAddress)) 
              gResponseIn = TRUE; 
           //check for Network Stas Response or Bridge Table Response 
           if(gResponseIn ||((pRsp->MEHDR == API_cReqNetStats)&&!(pRsp->DATA[0]&0x80)) 
                          ||((pRsp->MEHDR == EK_cBridgeChar)&&!(pRsp->DATA[0]&0x80))) 
           { 
               memcpy(localDev.Mac_Addr, pRsp->SA, kAddrSize);   // save address 
               localDev.Present = TRUE;    // mark as present 
               if(pRsp->MEHDR == API_cReqNetStats) 
               { 
                   localDev.Type = pRsp->DATA[0] & 0x7f;    //save device type 
                   if(localDev.Type > API_cINT5130A1 && localDev.Type < API_cINT5130A2) 
                      isEEPROMValid();     //check the EEPROM validity 
                   else 
                      localDev.Present = FALSE;    //can't talk to him 
               } 
           } 
           //check for a EEPROM/RAM read response 
           pEEPROM_Rsp = (SLP_FrameRsp_t*)ppktbuf->PacketBuffer; 
           if((pEEPROM_Rsp->Ethertype == API_cIntellonMacType) && 
              (pEEPROM_Rsp->MEHDR == EK_cSLP) && 
              (pEEPROM_Rsp->MELEN == EK_cLocalParamReturnSize) && 
              (pEEPROM_Rsp->CTRL == 1)) 
           {//EEPROM is valid, mark it and save it 
              localDev.EEPROMValid = TRUE; 
              memcpy(localDev.EEPROM, pEEPROM_Rsp->DATA, API_cLocalParamReturnSize-1); 
           } 
       } 
    }//if(ppktbuf != NULL) 
    return ppktbuf; 
} 
 
BOOLEAN sameMacAddress(MACAddress macAddr1, MACAddress macAddr2) 
{ 
    BOOLEAN same = FALSE; 
    int i; 
 
    for(i = 0; i < kAddrSize; i++) 
    { 
       if(macAddr1[i] != macAddr2[i]) 
          break; 
    } 
    if(i == kAddrSize) 
       same = TRUE; 
    return same; 
} 
 
//this function issues a read EEPROM MME.(actually set local parameters) 
//waits for a response(up to 3 times) 
void isEEPROMValid() 
{ 
    INT8U retries; 
    INT8U pRsp[1514]; 
    MACAddress DA, SA; 
 
    memcpy(DA, gBroadcastAddress, kAddrSize); 
    memcpy(SA, netif_list->hwaddr, kAddrSize); 
    for(retries = 0; retries < 3; retries++) 
    { 
        //issue SLP MME read EEPROM 
        sendLocalParam(SA, DA, API_cReadEEPROM); 
        //wait for a response 
        if(readAndFlip(50 + (retries*4), pRsp)) 
        { 
            gGlobalRetry = 0; 
            break; 
        } 
 
    } 
    if(retries == 3 && gGlobalRetry == 3) 
    {//device does not respond 
        gGlobalRetry = 0; 
        localDev.EEPROMValid = FALSE; 
    } 
    else 
        gGlobalRetry++; 
} 
 
//sends Set Local Parameters MME 
//para: CTRL - Control field for SLP MME - selects type of operation to perform 
//TRUE = success, FALSE = error occured 
BOOLEAN sendLocalParam(MACAddress SA, MACAddress DA, INT8U CTRL) 
{ 
   SLP_Frame_t  buffer; 
   SLP_Frame_t *pIf = &buffer; 
 
   memset(pIf, 0, sizeof(REQ_Frame_t)); 
   memcpy(pIf->DA, DA, kAddrSize); 
   memcpy(pIf->SA, SA, kAddrSize); 
   pIf->Ethertype = API_cIntellonMacType; 
   pIf->MCTRL = 0x01;     //frame contains 1 Mac Management entry 
   pIf->MEHDR = API_cSLP; 
   pIf->MELEN = API_cSLPSize; 
   pIf->CTRL = CTRL; 
   return PCA_bWrite(pIf, sizeof(buffer)); 
} 
 
BOOLEAN viperIsLocal() 
{ 
    BOOLEAN isAViper = FALSE; 
 
    gLocalMACSet = FALSE; 
    viperRequestDeviceDescription(); 
    viperWaitForResponse(NULL); 
    isAViper = gLocalMACSet; 
 
    return isAViper; 
} 
 
void viperRequestDeviceDescription() 
{ 
   sendPrivateMME(gBroadcastAddress, 16, NULL, 1); 
} 
 
//MACsendVendorCommandPacket (or sendVendorSpecificMME(VS_MME)) 
void sendPrivateMME(MACAddress DA, char mid, char *dataPtr, INT8U dataLen) 
{ 
   MACAddress SA; 
   int i, status; 
   Private_MME mme; 
 
   memcpy(SA, netif_list->hwaddr, kAddrSize); 
   memset(&mme, 0, sizeof(REQ_Frame_t)); 
   memcpy(mme.DA, DA, kAddrSize); 
   memcpy(mme.SA, SA, kAddrSize); 
   mme.Ethertype = API_cIntellonMacType; 
   mme.numEntries = 0x01; 
   mme.MMEHeader = 0x02; 
   mme.MMELength = (INT8U)(4 + dataLen); 
   mme.MMEOUI[0] = 0x00; 
   mme.MMEOUI[1] = 0x04; 
   mme.MMEOUI[2] = 0x87; 
   mme.MID       = mid; 
   mme.data[0]   = 0; 
   if(dataPtr) 
   { 
      for(i = 0; i < dataLen; i++) 
         mme.data[i] = dataPtr[i]; 
   } 
   status = PCA_bWrite(&mme, sizeof(Private_MME)); 
} 
 
void viperRequestMACVersion() 
{ 
    int status; 
    MAC_Host_MME frame; 
    MACAddress SA, DA; 
 
    memcpy(SA, netif_list->hwaddr, kAddrSize); 
    memcpy(DA, localDev.Mac_Addr, kAddrSize); 
    memset(&frame, 0, sizeof(REQ_Frame_t)); 
    memcpy(frame.DA, DA, kAddrSize); 
    memcpy(frame.SA, SA, kAddrSize); 
    frame.Ethertype = API_cIntellonMacType; 
    frame.numEntries = 0x01; 
    frame.MEHDR = 0x12;   //Host MME 
    frame.MELEN = 1; 
    frame.MID = 32; 
 
    status = PCA_bWrite(&frame, sizeof(MAC_Host_MME)); 
} 
 
BOOLEAN viperRequestNetStats() 
{ 
    char rxTx = 0; 
    MACAddress da; 
 
    memcpy(da, localDev.Mac_Addr, kAddrSize); 
    sendPrivateMME(da, 24, &rxTx, 1); 
    viperReadResponse(NULL); 
 
    return 1; 
} 
 
BOOLEAN viperWaitForResponse(char *data) 
{ 
   INT32U timeout; 
   BOOLEAN result; 
 
   timeout = OSTimeGet() + OS_TICKS_PER_SEC * (30 + 500L / OS_TICKS_PER_SEC) / 1000L; 
   do{ 
      OSTimeDly(1); 
      result = viperReadResponse(data); 
   }while(OSTimeGet() < timeout); 
 
   return result; 
} 
 
BOOLEAN viperReadResponse(char *message) 
{ 
    INT8U packet[1514]; 
    int dataLen; 
    MAC_Host_MME *pRsp; 
    BOOLEAN status = FALSE; 
    Private_MME *mmePtr; 
 
    //read the response frame 
    while(receiveFrame(packet, &dataLen)) 
    { 
        status = FALSE; 
        pRsp = (MAC_Host_MME*)packet; 
        if(pRsp->Ethertype != Swap2Bytes(kIntellonMacType)) 
            break; 
        switch(pRsp->MEHDR) 
        { 
           //response from viper! 
           case 0x13:    // METYPE_MAC_MME response from a MID=12 sent 
              break; 
 
           case 0x12:    //METYPE_HOST_MME 
              status = TRUE; 
              break; 
 
           //private vendor specific MME 
           case 0x02: 
              mmePtr = (Private_MME*)packet; 
              if(!(mmePtr->MID & 0x80)) 
                 break;   //response bit not set 
              mmePtr->MID &= 0x7F;   //mask off response bit 
              switch(mmePtr->MID) 
              { 
                 case 16:  //raw MID==144==128+16 
                    readDeviceDescriptionResponse(mmePtr); 
                    status = TRUE; 
                    break; 
 
                 case 24:  //raw MID==152==128+24 
                    //viperReadQualityResponse(mmePtr); 
                    status = TRUE; 
                    break; 
 
                 case 35: 
                    if(message != NULL) 
                       sprintf(message, "Extended Stats response recieved (%d).", pRsp->MID); 
                    break; 
 
                 default: 
                    if(message != NULL) 
                       sprintf(message, "Unknown private response recieved (%d).", pRsp->MID); 
               }//switch(mmePtr->MID) 
               break; 
 
           default: 
              //status = processHomePlugResponse(packet); 
              break; 
        }//switch(pRsp->MEHDR) 
        OSTimeDly(1); 
    }//while 
    return status; 
} 
 
BOOLEAN receiveFrame(INT8U *p, int *dataLen) 
{ 
   RSP_NET_Frame_t *pRsp; 
   struct ReceivePackage_t *rxPacket; 
   INT8U *src; 
 
   rxPacket = rx(); 
   //see if we have to fix the bridge 
   if(gResponseIn) 
      gResponseIn = FALSE; 
   if(rxPacket!= NULL) 
   { 
       pRsp = (RSP_NET_Frame_t*)rxPacket->PacketBuffer; 
       if(pRsp->Ethertype == API_cIntellonMacType) 
       { 
          src =(INT8U*)rxPacket->PacketBuffer; 
          //copy the frame to the message buffer 
          memcpy(p,src, rxPacket->nBytesReturned); 
          *dataLen = rxPacket->nBytesReturned; 
       } 
       return TRUE; 
   } 
   //no packets received 
   return FALSE; 
} 
 
void readDeviceDescriptionResponse(Private_MME *mmePtr) 
{ 
   char firmwareVersion[80]; 
   int vMajor, vMinor, vIncr, vBuild; 
   INT32U versionField; 
 
   if(mmePtr->vendor.flags & 0x02) 
   {//MME contains a "real" version 
      versionField = *(INT32U*)mmePtr->vendor.MACVersion; 
      vMajor = versionField & 0xf0000000 >> 28; 
      vMinor = versionField & 0x0ff00000 >> 20; 
      vIncr = versionField & 0x000ff000 >> 12; 
      vBuild = versionField & 0x00000fff; 
      sprintf(firmwareVersion, "%d-%d-%d-%d", vMajor, vMinor, vIncr, vBuild); 
   } 
   else 
      strcpy(firmwareVersion, "1.2-Alpha"); 
   //lsb contain remote/local bit flag 
   if(mmePtr->vendor.flags & 0x01) 
   {//1==remote 
   } 
   else 
   { 
      memcpy(localDev.Mac_Addr, mmePtr->SA, kAddrSize); 
      gLocalMACSet = TRUE; 
   } 
} 
 
/* 
struct pbuf *rico_mac_input_lan(struct netif *ethernetif) 
{ 
#if OS_CRITICAL_METHOD == 3                      // Allocate storage for CPU status register 
    OS_CPU_SR  cpu_sr; 
#endif 
    TX_FRAME_DES    *ptr_recv_desc; 
    INT32U t1; 
    void far *pktAddr; 
    INT16U pktLen; 
    struct pbuf *ppktbuf; 
 
    ptr_recv_desc = sq_mac_struct.recv_desc_point; 
 
    t1 = OSTimeGet() + 3; 
    while(ptr_recv_desc->tx_status & 0x80) 
    { 
       outport(0x900, 0x31); 
       outport(0x904, 0x01); 
       low_task_count = 50; 
       if(OSTimeGet() > t1) 
          break; 
    } 
    if(ptr_recv_desc->tx_status & 0x80) 
    { 
       return NULL; 
    } 
    low_task_count = 50; 
    pack_time_out = 0; 
    OS_ENTER_CRITICAL(); 
    if(ptr_recv_desc->tx_next_desc_offset == 1) 
       sq_mac_struct.recv_desc_point++; 
    else 
       sq_mac_struct.recv_desc_point = (TX_FRAME_DES*)0x00100000; 
    if(ptr_recv_desc->tx_status & 0x7701) 
    { 
       ptr_recv_desc->tx_status = 0x80; 
       OS_EXIT_CRITICAL(); 
       return NULL; 
    } 
    pktLen = Swap2Bytes(ptr_recv_desc->tx_head_leng); 
    ppktbuf = pbuf_alloc(PBUF_RAW, pktLen, PBUF_POOL); 
    if(!ppktbuf) 
    { 
       ptr_recv_desc->tx_status = 0x80; 
       OS_EXIT_CRITICAL(); 
       return NULL; 
    } 
    pktAddr = (void*)(((ptr_recv_desc->tx_data_addr & 0x000000ff) << 24)|((ptr_recv_desc->tx_data_addr & 0x0000ff00) << 8)| 
              ((ptr_recv_desc->tx_data_addr & 0x00ff0000) >> 8)|((ptr_recv_desc->tx_data_addr & 0xff000000) >> 24)); 
    memcpy((INT8U*)ppktbuf->payload, pktAddr, pktLen); 
    ppktbuf->len = pktLen; 
    ptr_recv_desc->tx_status = 0x80; 
    OS_EXIT_CRITICAL(); 
    return ppktbuf; 
} 
 
struct pbuf *rico_low_level_input(struct netif *pIf) 
{ 
   struct pbuf *rxPacket; 
 
   if((rxPacket = rico_mac_input_lan(pIf)) == NULL) 
   { 
       //netif_inout_status.driver_err_count++; 
       return NULL; 
   } 
   netif_inout_status.recv_pack++; 
   if((netif_inout_status.recv_pack_len[0] += rxPacket->tot_len) < rxPacket->tot_len) 
      netif_inout_status.recv_pack_len[1]++;    //64位加法 
 
   return rxPacket; 
} 
*/ 
#endif