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