//Mailbox Read Steps: //1. Interrupt going from the QCA4002 to the SPI host. //2. INTERNAL read from INTR_CAUSE register. //3. INTERNAL read from RDBUF_BYTE_AVA register. //4. Internal read from RDBUF_LOOKAHEAD1 register //5. Internal read from RDBUF_LOOKAHEAD2 register. From the 4 bytes we have read from RDBUF_LOOKAHEAD registers, get the packet size. //6. INTERNAL write to DMA_SIZE register with the packet size. //7. Start DMA read command and start reading the data by de-asserting chip select pin. //8. The packet available will be cleared by HW at the end of the DMA read. // AJ_EXPORT AJ_Status AJ_WSL_ReadFromMBox(uint8_t box, uint16_t* len, uint8_t** buf) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t cause = 0; uint16_t bytesInBuffer = 0; uint16_t bytesToRead = 0; uint16_t lookAhead; uint16_t payloadLength; AJ_ASSERT(0 == box); AJ_EnterCriticalRegion(); //2. INTERNAL read from INTR_CAUSE register. do { //3. INTERNAL read from RDBUF_BYTE_AVA register. status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_BYTE_AVA, &bytesInBuffer); AJ_ASSERT(status == AJ_OK); //bytesInBuffer = CPU_TO_BE16(bytesInBuffer); // The first few bytes of the packet can now be examined and the right amount of data read from the target //4. Internal read from RDBUF_LOOKAHEAD1 register //5. Internal read from RDBUF_LOOKAHEAD2 register. From the 4 bytes we have read from RDBUF_LOOKAHEAD registers, get the packet size. status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD1, &lookAhead); AJ_ASSERT(status == AJ_OK); lookAhead = CPU_TO_BE16(lookAhead); status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD2, &payloadLength); AJ_ASSERT(status == AJ_OK); payloadLength = CPU_TO_BE16(payloadLength); // calculate number of bytes to read from the lookahead info, and round up to the next block size bytesToRead = payloadLength + 6; //sizeof(header); bytesToRead = ((bytesToRead / AJ_WSL_MBOX_BLOCK_SIZE) + ((bytesToRead % AJ_WSL_MBOX_BLOCK_SIZE) ? 1 : 0)) * AJ_WSL_MBOX_BLOCK_SIZE; *buf = (uint8_t*)AJ_WSL_Malloc(bytesToRead); *len = bytesToRead; //6. INTERNAL write to DMA_SIZE register with the packet size. // write size to be transferred status = AJ_WSL_SetDMABufferSize(bytesToRead); AJ_ASSERT(status == AJ_OK); AJ_WSL_SPI_ReadIntoBuffer(bytesToRead, buf); // clear the packet available interrupt cause = 0x1; status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, cause); AJ_ASSERT(status == AJ_OK); break; } while (0); AJ_LeaveCriticalRegion(); return status; }
int8_t IP_GenerateUnicast(uint8_t packet[], IP_Protocol_t protocol, const IP_Address_t *destinationIP, uint8_t payloadLength) { const IP_Address_t *routerIP = destinationIP; if(!(IP_compareNet(&OwnIPAddress, destinationIP))) routerIP = &RouterIPAddress; int8_t offset = Ethernet_GenerateUnicast(packet, routerIP, CPU_TO_BE16(ETHERTYPE_IPV4)); if(offset <= 0) return offset; return offset + IP_WriteHeader(packet + offset, protocol, destinationIP, payloadLength); }
uint16_t IP_Checksum(const void *data, uint16_t length) { const uint16_t *Words = (const uint16_t *)data; uint16_t length16 = length / 2; uint16_t Checksum = 0; while(length16--) IP_ChecksumAdd(&Checksum, *(Words++)); if(length & 1) IP_ChecksumAdd(&Checksum, *Words & CPU_TO_BE16(0xFF00)); return ~Checksum; }
bool ICMP_ProcessPacket(uint8_t packet[]) { // Length is already checked ICMP_Header_t *ICMP = (ICMP_Header_t *)packet; if(ICMP->Type != ICMP_Echo_Request || ICMP->Code != ICMP_ECHO_Code) return false; // Answer Request: Leave Packet as is, only replace Type ICMP->Type = ICMP_Echo_Reply; // Adjust Checksum, only difference is Request(8)-Reply(0) at high byte IP_ChecksumAdd(&ICMP->Checksum, CPU_TO_BE16((ICMP_Echo_Request - ICMP_Echo_Reply) << 8)); return true; }
AJ_Status AJ_WSL_SPI_RegisterRead(uint16_t reg, uint8_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_READ; uint8_t pcs = AJ_WSL_SPI_PCS; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_READ; send.cmd_reg = AJ_WSL_SPI_INTERNAL; send.cmd_addr = reg; /* Test write: should return OK. */ rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); // toss. AJ_ASSERT(rc == SPI_OK); // read the first byte of response rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0 /*xFF*/, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); // junk to write while reading AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); AJ_ASSERT(rc == SPI_OK); status = AJ_OK; } // read the second byte spi_data++; rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0 /*xFF*/, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); // junk to write while reading AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); AJ_ASSERT(rc == SPI_OK); status = AJ_OK; } spi_data--; // move back to the original location *(uint16_t*)spi_data = CPU_TO_BE16(*(uint16_t*)spi_data); return status; }
static uint8_t IP_WriteHeader(uint8_t packet[], IP_Protocol_t protocol, const IP_Address_t *destinationIP, uint16_t payloadLength) { IP_Header_t *IP = (IP_Header_t *)packet; IP->Version_IHL = IP_VERSION_IHL; IP->TypeOfService = 0; IP->Length = cpu_to_be16(sizeof(IP_Header_t) + payloadLength); IP->Identification = 0; IP->FlagsFragment = CPU_TO_BE16(IP_FLAGS_DONTFRAGMENT); IP->TTL = DEFAULT_TTL; IP->Protocol = protocol; IP->DestinationAddress = *destinationIP; // Can be an alias of IP->SourceAddress IP->SourceAddress = OwnIPAddress; IP->Checksum = 0; // First set it to 0, then calculate correct checksum IP->Checksum = IP_Checksum(IP, sizeof(IP_Header_t)); return sizeof(IP_Header_t); }
bool IP_ProcessPacket(uint8_t packet[], uint16_t length) { // Minimum length is already checked IP_Header_t *IP = (IP_Header_t *)packet; // Remove optional padding uint16_t ip_length = be16_to_cpu(IP->Length); if(IP->Version_IHL != IP_VERSION_IHL || (IP->FlagsFragment & CPU_TO_BE16(0x3FFF) || ip_length > length)) return false; if(IP->DestinationAddress != OwnIPAddress && IP->DestinationAddress != BroadcastIPAddress) return false; length = ip_length - sizeof(IP_Header_t); bool reflect; switch (IP->Protocol) { case IP_PROTOCOL_ICMP: reflect = ICMP_ProcessPacket(IP->data); break; case IP_PROTOCOL_UDP: reflect = UDP_ProcessPacket(IP->data, &IP->SourceAddress, length); break; default: return false; } if(reflect) // rewrite Header, replace destination with sourceAddress { IP_WriteHeader(packet, IP->Protocol, &IP->SourceAddress, length); return true; } else { return false; } }
uint8_t IP_GenerateBroadcast(uint8_t packet[], IP_Protocol_t protocol, uint8_t payloadLength) { uint8_t offset = Ethernet_GenerateBroadcast(packet, CPU_TO_BE16(ETHERTYPE_IPV4)); return offset + IP_WriteHeader(packet + offset, protocol, &BroadcastIPAddress, payloadLength); }
* by the Serial Port service in its text string attributes. */ static const struct { SDP_ItemSequence8Bit_t LanguageEncoding_Header; struct { SDP_Item16Bit_t LanguageID; SDP_Item16Bit_t EncodingID; SDP_Item16Bit_t OffsetID; } LanguageEncoding; } ATTR_PACKED PROGMEM SerialPort_Attribute_LanguageBaseIDOffset = { SDP_ITEMSEQUENCE8BIT(sizeof(SerialPort_Attribute_LanguageBaseIDOffset.LanguageEncoding)), { SDP_ITEM16BIT(SDP_DATATYPE_UnsignedInt, CPU_TO_BE16(0x454E)), SDP_ITEM16BIT(SDP_DATATYPE_UnsignedInt, CPU_TO_BE16(0x006A)), SDP_ITEM16BIT(SDP_DATATYPE_UnsignedInt, CPU_TO_BE16(0x0100)), }, }; /** Serial Port Profile attribute, listing a human readable name of the service. */ static const struct { SDP_ItemString8Bit_t Text_Header; char Text[]; } ATTR_PACKED PROGMEM SerialPort_Attribute_ServiceName = { SDP_ITEMSTRING("Wireless Serial Port"), };
static void run_wsl_htc_parsing(const struct test_case* test) { /* * create a chain of buffers that simulate each protocol layer wrapping the layer above it. * The values chosen to populate the buffers are not legal protocol values, they just show * where the bytes are laid out in memory. */ AJ_BufList* list2 = AJ_BufListCreate(); AJ_BufNode* pNodeAppData = AJ_BufListCreateNodeZero(16, 1); AJ_BufNode_WMI* pNodeWMI; AJ_BufNode* pNodeWMITrail; AJ_BufNode* pNodeHTC; wsl_htc_msg_connect_service* msgConnectService; AJ_BufNode* pNodeHTCTrail; AJ_BufNode* pNodeHTCHeader; wsl_htc_hdr* msgHdr; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); strcpy((char*)pNodeAppData->buffer, "AppData string"); pNodeWMI = AJ_BufListCreateNode(sizeof(wsl_spi_command)); // stuff the buffer with a command. ((wsl_spi_command*)pNodeWMI->buffer)->cmd_addr = AJ_WSL_SPI_SPI_STATUS; ((wsl_spi_command*)pNodeWMI->buffer)->cmd_rx = 1; ((wsl_spi_command*)pNodeWMI->buffer)->cmd_reg = 1; *((uint16_t*)pNodeWMI->buffer) = CPU_TO_BE16(*(uint16_t*)pNodeWMI->buffer); // Swap the bytes around // create a bogus trailer pNodeWMITrail = AJ_BufListCreateNode(8); memset(pNodeWMITrail->buffer, 0xA1, 8); // create an HTC command pNodeHTC = AJ_BufListCreateNode(sizeof(wsl_htc_msg_connect_service)); msgConnectService = (wsl_htc_msg_connect_service*)pNodeHTC->buffer; msgConnectService->msg.messageID = AJ_WSL_HTC_CONNECT_SERVICE_ID; msgConnectService->serviceID = 0x5678; // random choice msgConnectService->flags = 0xCDEF; // random choice msgConnectService->serviceMetadataLength = 0; // random choice msgConnectService->metadata = 0; // random choice AJ_WSL_HTC_MSG_CONNECT_TO_WIRE(msgConnectService); // create another bogus trailer pNodeHTCTrail = AJ_BufListCreateNode(8); memset(pNodeHTCTrail->buffer, 0xB2, 8); // AppData was added then WMI was added, then HTC wrapped around that AJ_BufListPushHead(list2, pNodeAppData); AJ_BufListPushHead(list2, pNodeWMI); AJ_BufListPushTail(list2, pNodeWMITrail); AJ_BufListPushHead(list2, pNodeHTC); AJ_BufListPushTail(list2, pNodeHTCTrail); // create an HTC header structure with the correct size field (based on the size of the data to send on the wire) pNodeHTCHeader = AJ_BufListCreateNode(sizeof(wsl_htc_hdr)); msgHdr = (wsl_htc_hdr*)pNodeHTCHeader->buffer; msgHdr->endpointID = AJ_WSL_HTC_CONTROL_ENDPOINT; msgHdr->flags = 0; msgHdr->controlBytes[0] = 0xAB; msgHdr->controlBytes[1] = 0xCD; msgHdr->payloadLength = AJ_BufListLengthOnWire(list2); AJ_WSL_HTC_HDR_TO_WIRE(msgHdr); AJ_AlwaysPrintf(("\n\nPayload size would be: %d\n\n", AJ_BufListLengthOnWire(list2))); AJ_BufListPushHead(list2, pNodeHTCHeader); AJ_AlwaysPrintf(("%s", "write this to the wire\n\n")); AJ_BufListIterateOnWire(AJ_BufListWriteToWire_Simulated, list2, &toTarget); AJ_AlwaysPrintf(("\n\nDone wire write, length on wire: %d\n\n", AJ_BufListLengthOnWire(list2))); AJ_BufListFree(list2, 1); /* { // simulate a number of reads from the SPI buffer fakeWireRead = fakeWireBuffer; uint16_t readBufferSize = sizeof(fakeWireBuffer); AJ_AlwaysPrintf(("%s", "Wire Bufer\n")); while (readBufferSize > 0) { uint8_t byteRead = AJ_BufListReadByteFromWire_Simulated(); AJ_AlwaysPrintf(("%02X ", byteRead)); readBufferSize--; } } */ toTarget.fakeWireRead = toTarget.fakeWireBuffer; // fakeWireRead = fakeWireBuffer; // reset the read pointer to the start of our buffer { wsl_htc_hdr htcHdr1; AJ_BufNode* pNodeHTCBody; wsl_htc_msg* htcMsg1; AJ_AlwaysPrintf(("%s", "Read HTC header from wire buffer\n")); AJ_BufListReadBytesFromWire_Simulated(sizeof(htcHdr1), (uint8_t*)&htcHdr1, &toTarget); // convert the fields to the correct endianness AJ_WSL_HTC_HDR_FROM_WIRE(&htcHdr1); AJ_AlwaysPrintf(("\n HTC Hdr payload length 0x%04x\n\n", htcHdr1.payloadLength)); AJ_AlwaysPrintf(("%s", "Read HTC from wire buffer\n")); pNodeHTCBody = AJ_BufListCreateNode(htcHdr1.payloadLength /*+ sizeof(wsl_htc_msg)*/); htcMsg1 = (wsl_htc_msg*)pNodeHTCBody->buffer; AJ_BufListReadBytesFromWire_Simulated(pNodeHTCBody->length, pNodeHTCBody->buffer, &toTarget); switch (htcHdr1.endpointID) { case AJ_WSL_HTC_CONTROL_ENDPOINT: AJ_AlwaysPrintf(("%s", "Read HTC control endpoint\n")); // break; case AJ_WSL_HTC_DATA_ENDPOINT1: case AJ_WSL_HTC_DATA_ENDPOINT2: case AJ_WSL_HTC_DATA_ENDPOINT3: case AJ_WSL_HTC_DATA_ENDPOINT4: AJ_AlwaysPrintf(("\n%s %d\n", "Read HTC data endpoint", htcHdr1.endpointID)); // TODO send the data up to the next API level AJ_WSL_WMI_PrintMessage(pNodeHTCBody); break; default: AJ_AlwaysPrintf(("%s %d", "UNKNOWN Endpoint", htcHdr1.endpointID)); break; } // AJ_BufListReadBytesFromWire_Simulated(pNodeHTCBody->length, pNodeHTCBody->buffer); AJ_WSL_HTC_MSG_FROM_WIRE(htcMsg1); switch (htcMsg1->messageID) { case AJ_WSL_HTC_MSG_READY_ID: { wsl_htc_msg_ready* htcMsgReady1 = (wsl_htc_msg_ready*)pNodeHTCBody->buffer; AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_MSG_READY_ID \n")); AJ_WSL_HTC_MSG_READY_FROM_WIRE(htcMsgReady1); AJ_AlwaysPrintf(("\n HTC connect service message 0x%04x, CreditCount 0x%04X CreditSize 0x%04X\n\n", htcMsgReady1->msg.messageID, htcMsgReady1->creditCount, htcMsgReady1->creditSize)); break; } case AJ_WSL_HTC_CONNECT_SERVICE_ID: { wsl_htc_msg_connect_service* htcMsgCS1 = (wsl_htc_msg_connect_service*) pNodeHTCBody->buffer; AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_CONNECT_SERVICE_ID \n")); AJ_WSL_HTC_MSG_CONNECT_FROM_WIRE(htcMsgCS1); AJ_AlwaysPrintf(("\n HTC connect service message 0x%04x, serviceID 0x%04X \n\n", htcMsgCS1->msg.messageID, htcMsgCS1->serviceID)); break; } case AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID: { wsl_htc_msg_service_connect_response* htcServiceConnectResponse1 = (wsl_htc_msg_service_connect_response*)pNodeHTCBody->buffer; AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID \n")); AJ_WSL_HTC_MSG_SERVICE_CONNECT_RESPONSE_FROM_WIRE(htcServiceConnectResponse1); AJ_AlwaysPrintf(("\n HTC service connect response 0x%04x, serviceID 0x%04X metadatalength 0x%04X\n\n", htcServiceConnectResponse1->msg.messageID, htcServiceConnectResponse1->serviceID, htcServiceConnectResponse1->serviceMetadataLength)); break; } case AJ_WSL_HTC_SETUP_COMPLETE_ID: { AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_SETUP_COMPLETE_ID \n")); break; } case AJ_WSL_HTC_HOST_READY_ID: { AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_HOST_READY_ID \n")); break; } default: { AJ_ASSERT(htcMsg1->messageID <= AJ_WSL_HTC_HOST_READY_ID); break; } } } }