Any one guide me how I disable built in CRC from Tinyos?
Go to the relevant receiveP module and remove the CRC check in there. For instance in the popular CC2420 transciever (used in TelosB) the CRC is checked in line 646 of the CC2420ReceiveP module (code excerpt from CC2420ReceiveP below).
// We may have received an ack that should be processed by Transmit
// buf[rxFrameLength] >> 7 checks the CRC
if ( ( buf[ rxFrameLength ] >> 7 ) && rx_buf ) {
uint8_t type = ( header->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7;
signal CC2420Receive.receive( type, m_p_rx_buf );
if ( type == IEEE154_TYPE_DATA ) {
post receiveDone_task();
return;
}
}
You should note the transceiver will still drop some bad packets although you can change it's configuration in various ways to make sure it lets more of the bad packets through.
Related
I've created a TCP server application using BSD sockets and NUCLEO-H743ZI2 development board with STM32CubeMX 5.6.0 & LwIP 2.0.3 in Keil-MDKARM.
I noticed that:
If a client connects and sends 11 bytes or more at first, server
receives the data correctly and read() responds displaying the data.
However, if client sends the first data lower than 11
bytes, read() function blocks even next received data is higher than 11 bytes, until client disconnects. After the disconnection, all the data queued is displayed.
Namely, if first data sent from a client to my server is lower than 11 bytes, event_callback for a rcvevent is not triggered until disconnection.
My aim is to make the server available to one byte reception.
I've pasted my Server task/thread below. Let me have your kind response at your earliest convenience and feel free to request other related files/libraries(lwip.h, lwipopts.h..).
Kind Regards
void StartTask01(void const * argument)
{
/* USER CODE BEGIN StartTask01 */
MX_LWIP_Init();
/*start a listening tcp server*/
int iServerSocket;
struct sockaddr_in address;
if ((iServerSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Socket could not be created\n");
}
else
{
address.sin_family = AF_INET;
address.sin_port = htons(80);
address.sin_addr.s_addr = INADDR_ANY;
if (bind(iServerSocket, (struct sockaddr *)&address, sizeof (address)) < 0)
{
printf("socket could not be bound\n");
}
else
{
listen(iServerSocket, MEMP_NUM_NETCONN);
}
}
/*server started listening*/
struct sockaddr_in remoteHost;
int newconn;
char caReadBuffer[1500];
memset(caReadBuffer, 0, 1500);
for(;;)
{
/*block until accepting an incoming connection*/
newconn = accept(iServerSocket, (struct sockaddr *)&remoteHost, (socklen_t *)(sizeof(remoteHost)));
if (newconn != -1)/*if accepted well*/
{
/*block until data arrives*/
read(newconn, caReadBuffer, sizeof(caReadBuffer));
printf("data read: %s\n", caReadBuffer);
memset(caReadBuffer, 0, 1500);
}
}
/* USER CODE END StartTask01 */
}
The problem that's causing this issue is that you only call read once on each connection. If you don't happen to receive all the data from that single call to read (which is entirely unpredictable), you will never call read on that connection again.
When you call read on a blocking TCP connection, it will only block if there is no data available. Otherwise, it will give you whatever data is available up to the maximum number of bytes you ask for. It will not wait for more data if only some is available. It's up to you to call read again if you didn't receive all the data you expected.
One your second iteration of the for loop, you overwrite newconn with a new connection. You don't close the old connection. So you have a socket leak.
SOLVED:
The problem is, my server was listening port 80. I changed it to port 7 and thankfully bug is resolved, now read() works as expected.
This bug let me think that LwIP had problems on listening that web(80) port instead of others. There should be a some kind of discrimination between listening some spectacular ports even for unimplemented protocols.
I want to read the values of some Cortex-A53 registers, such as
D_AA64ISAR0_EL1 (AArch64)
ID_ISAR5 (Aarch32)
ID_ISAR5_EL1 (Aarch64)
Unfortunately, I lack a little embedded/assembly experience. The documentation reveals
To access the ID_AA64ISAR0_EL1:
MRS , ID_AA64ISAR0_EL1 ; Read ID_AA64ISAR0_EL1 into Xt
ID_AA64ISAR0_EL1[31:0] can be accessed through the internal memory-mapped interface
and the external debug interface, offset 0xD30.
I decided to utilize devmem2 on my target (since busybox does not include the devmem applet). Is the following procecure correct to read the register?
devmem2 0xD30
The part which I am unsure about is using the "offset" as a direct physical address. If it is the actual address, why call if "offset" and not "address". If it's an offset, what is the base address? I am 99% certain this is not the correct procedure, but how do I know the base address to add the offset to? I have searched the Armv8 technical reference manual and A53 MPCore documents to no avail. The explain the register contents in detail but seem to assume you read them from ASM using the label ID_AA64ISAR0_EL1.
Update:
I found this:
Configuration Base Address Register, EL1
The CBAR_EL1 characteristics are:
Purpose Holds the physical base address of the memory-mapped GIC CPU
interface registers.
But it simply duplicates my problem, how to read this other register?
Update 2:
The first update seems relevant only for GIC and not for configuration registers I am trying to read (I misunderstood the information I think).
For the specific problem at hand (checking crypto extension availability) one may simply cat /proc/cpuinfo and look for aes/sha etc.
Update 3:
I am now investigating http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0176c/ar01s04s01.html, as well as the base address being SoC specific and thus may be found in the reference manual of the SoC.
Update 4:
Thanks to the great answer I seem to be able to read data via my kernel module:
[ 4943.461948] ID_AA64ISA_EL1 : 0x11120
[ 4943.465775] ID_ISAR5_EL1 : 0x11121
P.S.: This was very insightful, thank you again!
Update 5:
Source code as per request:
/******************************************************************************
*
* Copyright (C) 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*****************************************************************************/
#include <linux/module.h>
#include <linux/types.h>
/*****************************************************************************/
// read system register value ID_AA64ISAR0_EL1 (s3_0_c0_c6_0).
static inline uint64_t system_read_ID_AA64ISAR0_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, ID_AA64ISAR0_EL1" : "=r" (val));
return val;
}
// read system register value ID_ISAR5_EL1 (s3_0_c0_c2_5).
static inline uint64_t system_read_ID_ISAR5_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c0_c2_5" : "=r" (val));
return val;
}
/*****************************************************************************/
int init_module(void)
{
printk("ramdump Hello World!\n");
printk("ID_AA64ISAR0_EL1 : 0x%llX\n", system_read_ID_AA64ISAR0_EL1());
printk("ID_ISAR5_EL1 : 0x%llX\n", system_read_ID_ISAR5_EL1());
return 0;
}
void cleanup_module(void)
{
printk("ramdump Goodbye Cruel World!\n");
}
MODULE_LICENSE("GPL");
Disclaimer: I am not an Aarch64 expert, but I am currently learning about the architecture and have read a bit.
You cannot read ID_AA64ISAR0_EL1, ID_ISAR5_EL1 nor ID_ISAR5 from a user-mode application running at EL0: the _EL1 suffix means than running at least at EL1 is required in order to be allowed to read those two registers.
You may find helpful to read the pseudo-code in the arm documentation here and here.
In the case of ID_ISAR5 for example, the pseudo-code is very explicit:
if PSTATE.EL == EL0 then
UNDEFINED;
elsif PSTATE.EL == EL1 then
if EL2Enabled() && !ELUsingAArch32(EL2) && HSTR_EL2.T0 == '1' then
AArch64.AArch32SystemAccessTrap(EL2, 0x03);
elsif EL2Enabled() && ELUsingAArch32(EL2) && HSTR.T0 == '1' then
AArch32.TakeHypTrapException(0x03);
elsif EL2Enabled() && !ELUsingAArch32(EL2) && HCR_EL2.TID3 == '1' then
AArch64.AArch32SystemAccessTrap(EL2, 0x03);
elsif EL2Enabled() && ELUsingAArch32(EL2) && HCR.TID3 == '1' then
AArch32.TakeHypTrapException(0x03);
else
return ID_ISAR5;
elsif PSTATE.EL == EL2 then
return ID_ISAR5;
elsif PSTATE.EL == EL3 then
return ID_ISAR5;
One easy way to read those register would be to write a tiny loadable kernel module you could call from your user-mode application: Since the Linux kernel is running at EL1, it is perfectly able to read those three registers.
See for example this article for a nice introduction to Linux loadable kernel modules.
And this is likely that an application running at EL0 cannot access memory-mapped registers accessible only from EL1, since this would obviously break the protection scheme.
The C code snippets required to read those registers in Aarch64 state would be (tested with gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu) :
#include <stdint.h>
// read system register value ID_AA64ISAR0_EL1 (s3_0_c0_c6_0).
static inline uint64_t system_read_ID_AA64ISAR0_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c0_c6_0" : "=r" (val));
return val;
}
// read system register value ID_ISAR5_EL1 (s3_0_c0_c2_5).
static inline uint64_t system_read_ID_ISAR5_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c0_c2_5" : "=r" (val));
return val;
}
Update #1:
The GCC toolchain does not understand all arm system register names, but can nevertheless properly encode system registers access instructions if specified which exact values of the coproc, opc1, CRn, CRm, and opc2 fields are associated to this register.
In the case of ID_AA64ISAR0_EL1, the values specified in the Arm® Architecture Registers Armv8, for Armv8-A architecture profile document are:
coproc=0b11, opc1=0b000, CRn=0b0000, CRm=0b0110, opc2=0b000
The system register alias would then be s[coproc]_[opc1]_c[CRn]_c[CRm]_[opc2], that is s3_0_c0_c6_0 in the case of ID_AA64ISAR0_EL1.
I see this tool maybe meets your need:
system-register-tools
It just provides reading and writing system registers function for arm64, likes MSR-tools in x86.
What we need to do
We need to detect both the presence and absence of an RFID chip. We intend to do this by continually checking for a card. If one is there, we read it and confirm which it is. If there isn't one there after there previously was, then that is noted. It doesn't have to be super fast.
What we're using
Arduino UNO + RC522 FRID reader, with MIFARE 1k cards. Using the library at: https://github.com/miguelbalboa/rfid
The problems
Cannot read multiple cards
Contrary to what seems to be stated in example code found elsewhere, I am never able to read more than one card without resetting the RC522. As soon as it reads a card, and it's HALTed, no more cards can be read until the processor is reset. Other examples suggest this shouldn't be the case and a new card should immediately be readable on the next loop. Using:
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid));
mfrc522.PICC_HaltA();
}
Successfully gives:
Card UID: B6 35 9F 46
Card SAK: 08
PICC type: MIFARE 1KB
But I cannot read any more cards until I reset the RF522 (either using software or just restarting the device).
Cannot authenticate card
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
}
Gives the following output
Card UID: B6 35 9F 46
Card SAK: 08
PICC type: MIFARE 1KB
Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits
15 63 PCD_Authenticate() failed: Timeout in communication.
14 59 PCD_Authenticate() failed: Timeout in communication.
13 55 PCD_Authenticate() failed: Timeout in communication.
...
Cannot read card when starting
I cannot read a card if it's present when starting the RC522, the communication times out. It does, however, take longer when a card is present. Using the following code:
// this is triggered by a serial command input
void resetAndRead() {
Serial.println("Init and check for any card");
mfrc522[0].PCD_Reset();
Serial.print("Reset complete (antenna off): ");
Serial.println(millis() - time_last_action);
delay(2000);
time_last_action = millis();
initialise();
Serial.print("Init complete: ");
Serial.println(millis() - time_last_action);
delay(10);
time_last_action = millis();
PICC_IsAnyCardPresent();
Serial.print("Check for card complete: ");
Serial.println(millis() - time_last_action);
}
void initialise() {
mfrc522[0].PCD_Init(ssPins[0], RST_PIN); // Init each MFRC522 card
mfrc522[0].PCD_DumpVersionToSerial();
}
bool PICC_IsAnyCardPresent() {
byte bufferATQA[2];
byte bufferSize = sizeof(bufferATQA);
MFRC522::StatusCode result = mfrc522[0].PICC_WakeupA(bufferATQA, &bufferSize);
Serial.print("Status Code: ");
Serial.print(mfrc522[0].GetStatusCodeName(result));
Serial.println();
return (result == MFRC522::STATUS_OK || result == MFRC522::STATUS_COLLISION);
}
I get the following output with no card present
Init and check for any card
Reset complete (antenna off): 50
Firmware Version: 0x92 = v2.0
Init complete: 51
Status Code: Timeout in communication.
Check for card complete: 41
And with a card present
Init and check for any card
Reset complete (antenna off): 52
Firmware Version: 0x92 = v2.0
Init complete: 53
Status Code: Timeout in communication.
Check for card complete: 294
The Questions
Particularly given the first issue - does this sound like a hardware issue? No one else seems to have problems reading multiple cards without requiring a reset.
Should it be possible to solve the third issue? i.e. should an RFID reader be able to communicate with an RFID chip when the antenna is first switched on.
You forgot exit an authentificated PICC. Try to use the MFRC522::PCD_StopCrypto1() function.
Used to exit the PCD from its authenticated state. Remember to call
this function after communicating with an authenticated PICC -
otherwise no new communications can start.
You can use the method after dumping the information:
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
or directly before checking a new card (multiple calls are no problem):
mfrc522.PICC_IsNewCardPresent()
Bit late,
but perhaps someone will find these usefull..
https://github.com/miguelbalboa/rfid/issues/269#issuecomment-292783655
https://github.com/miguelbalboa/rfid/issues/269#issuecomment-472342583
// Function requires an integer assigned to specific reader
// If not multi-reader, just drop the [...]
void mfrc522_fast_Reset(int reader) {
digitalWrite(RST_PIN, HIGH);
mfrc522[reader].PCD_Reset();
mfrc522[reader].PCD_WriteRegister(mfrc522[reader].TModeReg, 0x80); // TAuto=1;
// Timer starts automatically at the end of the transmission
// in all communication modes at all speeds
mfrc522[reader].PCD_WriteRegister(mfrc522[reader].TPrescalerReg, 0x43); // 10μs.
// mfrc522.PCD_WriteRegister(mfrc522.TPrescalerReg, 0x20); // test
mfrc522[reader].PCD_WriteRegister(mfrc522[reader].TReloadRegH, 0x00);
// Reload timer with 0x064 = 30, ie 0.3ms before timeout.
mfrc522[reader].PCD_WriteRegister(mfrc522[reader].TReloadRegL, 0x1E);
//mfrc522.PCD_WriteRegister(mfrc522.TReloadRegL, 0x1E);
mfrc522[reader].PCD_WriteRegister(mfrc522[reader].TxASKReg, 0x40);
// Default 0x00. Force a 100 % ASK modulation independent
//of the ModGsPReg register setting
mfrc522[reader].PCD_WriteRegister(mfrc522[reader].ModeReg, 0x3D);
// Default 0x3F. Set the preset value for the CRC coprocessor
// for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4)
mfrc522[reader].PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2
// (they were disabled by the reset)
}
I want to read the data through socket in Qt. I am using QBytearray to store the data. Actually server sends 4095 bytes in a single stretch, but in the QT client side I am receiving in different chunks because of my application design.
void Dialog::on_pushButton_clicked()
{
socket=new QTcpSocket(this);
socket->connectToHost("172.17.0.1",5000);
if(socket->waitForConnected(-1))
qDebug()<<"Connected";
Read_data();
}
void Dialog::Read_data()
{
QString filename(QString("%1/%2.bin").arg(path,device));
qDebug()<<"filename"<<filename;
QFile fileobj(filename);
int cmd,file_size,percentage_completed;
if(!fileobj.open(QFile::WriteOnly | QFile::Text))
{
qDebug()<<"Cannot open file for writting";
return;
}
QTextStream out(&fileobj);
while(1)
{
socket->waitForReadyRead(-1);
byteArray=socket->read(4);
qDebug()<<"size of bytearray"<<byteArray.size();
length=0xffff & ((byteArray[3]<<8)|(0x00ff & byteArray[2]));
int rem;
byteArray=socket->read(length);
while(byteArray.size()!=length)
{
rem=length-byteArray.size();
byteArray.append( socket->read(rem));
}
fileobj.write(byteArray);
fileobj.flush();
byteArray.clear();
}
}
server code:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<mtd/mtd-user.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include<math.h>
#include <netinet/tcp.h>
static int msb,lsb,size,listenfd = 0, connfd = 0,len;
main()
{
struct sockaddr_in serv_addr;
serverlen=sizeof(serv_addr);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
if(bind(listenfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
{
perror("\n Error in binding");
exit(1);
}
size=100000;
listen(listenfd, 1);
fd=fopen(new.bin,"r");
len=4089;
while(1)
{
buff[0]=25;
buff[1]=2;
buff[2]=60;
buff[3]=47;
n=fread(buff+4,1,length, fd);
buff[len+4]=5;
buff[len+5]='\n';
if(n>0)
sent_bytes=send(connfd,buff,n+6,0);
size =size-len;
if(size==0)
break;
}
}
If I execute the code in localhost(127.0.0.1) I can receive the data fully. The problem arises only when I connect to different host IP. Kindly help me in this regard
EDIT 1:
The problem is when bytesAvailable() returns the maximum bytes I am waiting for waitForReadyRead() times out. It works fine if the bytesAvailable() is less than as expected. Does bytesAvailable() allocate any buffer annoyed by this behaviour.
while(1)
{
while(socket->bytesAvailable()<4)
{
if (!socket->waitForReadyRead())
{
qDebug() << "waitForReadyRead() timed out";
return;
}
}
byteArray=socket->read(4);
length=0xffff & ((byteArray[3]<<8)|(0x00ff & byteArray[2]));
int rem_bytes=length+2;
qDebug()<<"bytes available"<<socket->bytesAvailable();
while(socket->bytesAvailable()<=rem_bytes)
{
qDebug()<<"reading";
if (!socket->waitForReadyRead(10000))//times out here if bytesAvailable() == rem_bytes but executes well in other cases
{
qDebug() << "waitForReadyRead() timed out";
return;
}
qDebug()<<"ready";
byteArray.append(socket->read(rem_bytes));
qDebug()<<"size of bytearray"<<byteArray.size();
if(byteArray.size()==length+2)
{
for(int j=0;j<length;j++)
newarray.append(byteArray[j]);
fileobj.write(newarray);
fileobj.flush();
newarray.clear();
byteArray.clear();
break;
}
else
{
rem_bytes -=byteArray.size();
}
}
Send();
}
I have tried by sending different data sizes cannot figure it out why?. Please provide me a solution pointing where I have gone wrong
Your problem stems from your misunderstanding of how TCP works.
When data is transmitted from a sender, it is broken into packets and then each packet is transmitted one by one until all the data has finished sending. If packets go missing, they are re-transmitted until either they reach their destination, or a timeout is reached.
As an added complication, each packet might follow various routes before arriving at the destination. The receiver has the task of acknowledging to the sender that packets have been received and then making sure that the packets are joined back together in the correct order.
For this reason, the longer the network route, the greater the chance of getting a delay in getting the data re-assembled. This is what you've been experiencing with your localhost versus networked-computer tests.
The IP stack on your computer does not wait for the complete data to arrive before passing it to your application but it will pause if it's missing a packet in sequence.
e.g. If you have 10 packets and packet 4 arrives last, the IP stack will pass the data to your application in two sets: 1-2-3, [[wait for 4 to arrive]], 4-5-6-7-8-9-10.
For this reason, when waitForReadyRead() returns true, you cannot expect that all your data has arrived, you must always check how many bytes have been actually received.
There are two places in your code where you wait for data. The first thing you wait for is a four-byte number to tell you how much data has been sent. Even though it's highly likely that you will have received all four bytes, it's good practice to check.
while(socket.bytesAvailable() < 4){
if (!socket.waitForReadyRead()) { // timeout after 30 second, by default
qDebug() << "waitForReadyRead() timed out";
return;
}
}
byteArray=socket->read(4);
qDebug()<<"size of bytearray"<<byteArray.size();
length=0xffff & ((byteArray[3]<<8)|(0x00ff & byteArray[2]));
The next thing you need to do is keep cycling through a wait-read-wait-read loop until all your data has arrived, each time keeping track of how many bytes you still expect to receive.
int bytesRemaining = length;
while(socket->bytesAvailable() < bytesRemaining){
if (!socket->waitForReadyRead()){
qDebug() "waitForReadyRead() timed out";
return;
}
// calling read() with the bytesRemaining argument will not guarantee
// that you will receive all the data. It only means that you will
// receive AT MOST bytesRemaining bytes.
byteArray = socket->read(bytesRemaining);
bytesRemaining -= byteArray.size();
fileobj.write(byteArray);
fileobj.flush();
}
All this said, you should not use the blocking API in your main thread or your GUI could freeze up. I suggest either using the asynchronous API, or create a worker thread to handle the downloading (and use the blocking API in the worker thread).
To see examples of how to use the two different APIs, looking in the documentation for the Fortune Client Example and the Blocking Fortune Client Example.
EDIT:
My apologies, there's a bug in the code above that doesn't take an number of possibilities into account, most importantly, if all data has already been received, and the end game once all data has finally arrived.
The following one-line change should clear that up:
Change
while(socket->bytesAvailable() < bytesRemaining){
To
while (bytesRemaining > 0) {
So you are saying that waitForReadyRead() returns false regardless of the time given once your the buffer has all 3000 expected bytes. What other behavior would you want? Perhaps you need rethink the trigger logic here. Many TCP/IP app protocols have some sort of frame start detection logic they combine with the required message size to then trigger processing. This lets them cope with widely different package sizes that the intermediate networks will impose, as well as truncated/partial messages. Once you have it working, connect to it by way of your cell phone and you will get different set of packet fragmentation examples to test with.
I want to retrieve some video data from a device with RTSP.
RTSP over UDP works well, but I need it over TCP.
After issuing the RTSP commands, I receive RTPs but I do not how to handle them here.
The payload is as follows: $[channel - 1 byte][length - 2bytes][data]
The thing is that I receive such packets and sometimes further packets where channel is 10 or 99 etc.
So could anyone please provide some input on how to handle the payload ?
You have it all in RFC 2326 "Real Time Streaming Protocol (RTSP)". You need "10.12 Embedded (Interleaved) Binary Data":
Stream data such as RTP packets is encapsulated by an ASCII dollar sign (24 hexadecimal), followed by a one-byte channel identifier, followed by the length of the encapsulated binary data as a binary, two-byte integer in network byte order. The stream data follows immediately afterwards, without a CRLF, but including the upper-layer protocol headers. Each $ block contains exactly one upper-layer protocol data unit, e.g., one RTP packet.
There is a small example there as well:
S->C: $\000{2 byte length}{"length" bytes data, w/RTP header}
S->C: $\000{2 byte length}{"length" bytes data, w/RTP header}
S->C: $\001{2 byte length}{"length" bytes RTCP packet}
Getting PPS is IMO straightforward and does not really require parseing the packet.
Your request for SPS , im guessing , will require getting into the packet ( i dont think you need to worry about WS msg 'invalid packet'.
What about using Type at PT at 0x09 ?
see here for packet description
sample implementations of unpacking RTP in the answer here
try looking here for more info related to RTSP control and SDP over TCP. If you are getting into inspecting the details of the RTSP session/conversation and the messaging details about control protocol selection for the respective tracks in your video. If u can get your answer without a diversion into SDP / RTCP then , obviously, thats faster/better.
this is the packet format for TCP/RTP :
[$ - 1byte][Transport Channel - 1byte][RTP data length - 2bytes][RTP data]
the rest is like upd
for more info read process raw rtp packets
Just explain something, I'm working for this as well, If you want use RTSP over TCP, please be careful about your socket reading code.
The suitable socket process like below:
while (socket.connected) {
char magic = socket.read a char;
if (magic == '$') { // is a RTP over TCP packet
byte channel = socket.read 1 byte;
unsigned short len = socket.read 2 byte; // len = ((byte1 & 0xFF) << 8) + (byte2 &0xFF);
int readTotal = 0;
byte rtpPacket[len];
while (readTotal < len) {
// read remaing bytes to rtpPacket from index readTotal
int r = socket.read(rtpPacket, readTotal, len - readTotal);
if (r > 0)
readTotal += r;
else // -1 means socket read error
break;
}
// now we get full RTP packet, process it!
call back channel, rtpPacket;
} else { // is RTSP protocol response
string array header;
while (line = socket.readline() != null) {
if (line == "") {
int body_len = Parse header "Content-Length";
byte body[body_len];
int readBody = 0;
while (readBody < body_len) {
int r = socket.read(body, readBody, body_len - readBody);
if (r>0)
readBody += r;
else
break;
}
// Now we get full header, body of RTSP response, process it
Callback header, body;
} else {
header.add(line);
}
}
}
}