How to read UDP packet data containing non-string elements? - ios

Im fairly new to IOS programming and objective-c. I have an embedded system that runs a program written in C that is sending UDP packet to iPhone app I am working on.
I am able to read the packet data (NSData) if it only contains a string but, cannot if the data is structured with additional markup.
Here is the C code that sends the packet.
typedef struct s_msg_temp_report {
uint8_t id0;
uint8_t id1;
uint8_t name[9];
uint8_t led;
uint32_t temp;
} t_msg_temp_report;
static t_msg_temp_report msg_temp_report =
{
.id0 = 0,
.id1 = 2,
.name = DEMO_PRODUCT_NAME,
.led = 0,
.temp = 0,
};
/* Send client report. */
msg_temp_report.temp = (uint32_t)(at30tse_read_temperature() * 100);
msg_temp_report.led = !port_pin_get_output_level(LED_0_PIN);
ret = sendto(tx_socket, &msg_temp_report, sizeof(t_msg_temp_report),
0,(struct sockaddr *)&addr, sizeof(addr));
if (ret == M2M_SUCCESS) {
puts("Assignment 3.3: sensor report sent");
} else {
puts("Assignment 3.3: failed to send status report !");
}
What is the best way to to process (NSData) object data into a usable object for string conversion?

Related

Query of Extraction and process of buffer_data from 4 channel PCM data buffer in STM32 Code

I am trying to understand one 4 channel mic-array code provided by ST(AMicArray_Microphones_Streaming).
In the code, the PCM buffer data is sent on the USB via this function. In this code, I actually want to do some processing on the received data and then I want to send it on USB. My question is how to extract the raw data and process them?
This topic seems very broad to a beginner person if someone can help me with some start material or guidelines would be appreciated.
//PCMSamples = AUDIO_IN_SAMPLING_FREQUENCY/1000*AUDIO_IN_CHANNELS;
uint8_t USBD_AUDIO_Data_Transfer(USBD_HandleTypeDef *pdev, int16_t * audioData, uint16_t PCMSamples)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if(haudioInstance.state==STATE_USB_WAITING_FOR_INIT){
return USBD_BUSY;
}
uint16_t dataAmount = PCMSamples * 2; /*Bytes*/
uint16_t true_dim = haudio->buffer_length;
uint16_t current_data_Amount = haudio->dataAmount;
uint16_t packet_dim = haudio->paketDimension;
if(haudio->state==STATE_USB_REQUESTS_STARTED || current_data_Amount!=dataAmount){
/*USB parameters definition, based on the amount of data passed*/
haudio->dataAmount=dataAmount;
uint16_t wr_rd_offset = (AUDIO_IN_PACKET_NUM/2) * dataAmount / packet_dim;
haudio->wr_ptr=wr_rd_offset * packet_dim;
haudio->rd_ptr = 0;
haudio->upper_treshold = wr_rd_offset + 1;
haudio->lower_treshold = wr_rd_offset - 1;
haudio->buffer_length = (packet_dim * (dataAmount / packet_dim) * AUDIO_IN_PACKET_NUM);
/*Memory allocation for data buffer, depending (also) on data amount passed to the transfer function*/
if(haudio->buffer != NULL)
{
USBD_free(haudio->buffer);
}
haudio->buffer = USBD_malloc(haudio->buffer_length + haudio->dataAmount);
if(haudio->buffer == NULL)
{
return USBD_FAIL;
}
memset(haudio->buffer,0,(haudio->buffer_length + haudio->dataAmount));
haudio->state=STATE_USB_BUFFER_WRITE_STARTED;
}else if(haudio->state==STATE_USB_BUFFER_WRITE_STARTED){
if(haudio->timeout++==TIMEOUT_VALUE){
haudio->state=STATE_USB_IDLE;
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->Stop();
haudio->timeout=0;
}
memcpy((uint8_t * )&haudio->buffer[haudio->wr_ptr], (uint8_t *)(audioData), dataAmount);
haudio->wr_ptr += dataAmount;
haudio->wr_ptr = haudio->wr_ptr % (true_dim);
if((haudio->wr_ptr-dataAmount) == 0){
memcpy((uint8_t *)(((uint8_t *)haudio->buffer)+true_dim),(uint8_t *)haudio->buffer, dataAmount);
}
}
return USBD_OK;
}
I am guessing you are using the X-Cube Audio library from ST, if so the
AudioProcess()
function in the Core/Src/audio_application.c file matches your needs.
void AudioProcess(void)
{
if (CCA02M2_AUDIO_IN_PDMToPCM(CCA02M2_AUDIO_INSTANCE,(uint16_t * )PDM_Buffer,(uint16_t *)PCM_Buffer) != BSP_ERROR_NONE)
{
Error_Handler();
}
Send_Audio_to_USB((int16_t *)PCM_Buffer, (AUDIO_IN_SAMPLING_FREQUENCY/1000)*AUDIO_IN_CHANNELS * N_MS);
}
The PDM and PCM data are available here for processing.
ST provides video tutorial on Audio acquisition here. You can refer their channel for more information.

Sending MIDI using MIDISendEventList() in C/C++

I've been working to migrate an older Core MIDI sending implementation to send MIDI 1.0 messages using Apple's newer UMP-aware MIDI Event List API methods.
I've figured out code that runs and should output MIDI clock messages, but when I send it with MIDISendEventList(...) I see nothing being output from my MIDI interface; there's also no error returned from that method to indicate what the problem is.
Here is the code I'm using:
const ByteCount clockMessageSize = 1;
const UInt32 clockMessage[clockMessageSize] = { (UInt32)0xF8 }; // MIDI clock tick
const MIDITimeStamp timeStamp = mach_absolute_time();
MIDIEventList clockMessageEventList = {};
MIDIEventPacket* clockMessageEventListEndPacket = nullptr;
clockMessageEventListEndPacket = MIDIEventListInit(&clockMessageEventList, kMIDIProtocol_1_0);
clockMessageEventListEndPacket = MIDIEventListAdd(&clockMessageEventList, sizeof(MIDIEventList::packet), clockMessageEventListEndPacket, timeStamp, clockMessageSize, clockMessage);
for (NSUInteger endpointRefIndex = 0; endpointRefIndex < endPointRefsCount; ++endpointRefIndex) {
MIDIObjectRef destinationEndpoint = endPointRefs[endpointRefIndex];
OSStatus midiSendError = MIDISendEventList(outputPortRef, destinationEndpoint, &clockMessageEventList);
if (midiSendError != noErr) {
printf("MIDISendEventList error: %i", (int)midiSendError);
}
}
Inspecting clockMessageEventList.packet after it has been configured but before it is sent shows:
(248, 0, 0, [... all zeros to index 63])
Does anyone know where I'm going wrong?

Read "structured/serialized data" from NSStream

I am developing a game app which will take structured data from a server and make responses based on these data.
I have connected the app to the internet through the NSSream. Specifically, I follow the tutorial of Apple's guide. So my code looks something like:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if(!_data) {
_data = [[NSMutableData data] retain];
}
uint8_t buf[1024];
NSInteger len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[_data appendBytes:(const void *)buf length:len];
// bytesRead is an instance variable of type NSNumber.
[bytesRead setIntValue:[bytesRead intValue]+len];
} else {
NSLog(#"no buffer!");
}
break;
}
// continued
My problem is: "How can I convert the _data to the format I want when it is possible". For example, my server will send two types of data. For each data, the first byte is an indicater for the data type (e.g., 1 means data type 1, 2 means data type 2). For the data type 1, an int (4 bytes) is sent as the data itself. For the data type 2, an int (4 bytes) is sent as the size of the following string bytes. For example, if this int is 10, then there will be 10 more bytes sent from the server to form a string for the client.
The code in my Android(Java) app looks like:
// dataIn = new DataInputStream(socket.getInputStream());
private void keepPacketRecving(){ // this will be executed in a separate thread
while(keepRecvThreadRunning) {
try {
byte type;
type = dataIn.readByte();
if(type == 1){
int data = dataIn.readInt();
getTye1Data(data); // callback function for receiving type 1 data (int)
} else if (type ==2) {
int dataSize = dataIn.readInt();
byte[] buf = new byte[dataSize];
// ... loop to read enough byte into buf ...
String data = new String(buf);
getType2Data(data); // callback function for receiving type 2 data (String)
}
}
}
}
I also notice I can't have a while-loop inside the switch statement to ask inputStream to read more data untile it is enougth because it will hang the thread.
I guess the best way would be always appending all the bytes into the _data (like the example) and has another function to parse the _data? Then the problem is how I can peek bytes from the data and just fetch part of it out (e.g., 10 bytes out of a 20-byte _data).
Is there any wrapper in Objective-C like the DataInputStream in Java?

Gstreamer - appsrc push model

I'm developing a C application (under linux) that receives a raw h.264 stream and should visualize this stream using gstreamer APIs.
I am a newbie with GStreamer so maybe I am doing huge stupid mistakes or ignoring well-known stuff, sorry about that.
I got a raw h264 video (I knew it was the exact same format I need) and developed an application that plays it. It correctly works with appsrc in pull mode (when need data is called, I get new data from the file and perform push-buffer).
Now I'm trying to do the exact same thing but in push mode, this is basically because I don't have a video, but a stream. So I have a method inside my code that will be called every time new data (in the form of an uint8_t buffer) arrives, and this is my video source.
I googled my problem and had a look at the documentation, but I found no simple code snippets for my use case, even if it seems a very simple one. I understood that I have to init the pipeline and appsrc and then only push-buffer when I have new data.
Well, I developed two methods: init_stream() for pipeline/appsrc initialization and populate_app(void *inBuf, size_t len) to send data when they are available.
It compiles and correctly runs, but no video:
struct _App
{
GstAppSrc *appsrc;
GstPipeline *pipeline;
GstElement *h264parse;
GstElement *mfw_vpudecoder;
GstElement *mfw_v4lsin;
GMainLoop *loop;
};
typedef struct _App App;
App s_app;
App *app = &s_app;
static gboolean bus_message (GstBus * bus, GstMessage * message, App * app)
{
GST_DEBUG ("got message %s", gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
g_error ("received error");
g_main_loop_quit (app->loop);
break;
case GST_MESSAGE_EOS:
g_main_loop_quit (app->loop);
break;
default:
break;
}
return TRUE;
}
int init_stream()
{
GstBus *bus;
gst_init (NULL, NULL);
fprintf(stderr, "gst_init done\n");
/* create a mainloop to get messages */
app->loop = g_main_loop_new (NULL, TRUE);
fprintf(stderr, "app loop initialized\n");
app->pipeline = gst_parse_launch("appsrc name=mysource ! h264parse ! mfw_vpudecoder ! mfw_v4lsin", NULL);
app->appsrc = gst_bin_get_by_name (GST_BIN(app->pipeline), "mysource");
gst_app_src_set_stream_type(app->appsrc, GST_APP_STREAM_TYPE_STREAM);
gst_app_src_set_emit_signals(app->appsrc, TRUE);
fprintf(stderr, "Pipeline and appsrc initialized\n");
/* Create Bus from pipeline */
bus = gst_pipeline_get_bus(app->pipeline);
fprintf(stderr, "bus created\n");
/* add watch for messages */
gst_bus_add_watch (bus, (GstBusFunc) bus_message, app);
gst_object_unref(bus);
fprintf(stderr, "bus_add_watch done\n");
GstCaps* video_caps = gst_caps_new_simple ("video/x-h264",
"width", G_TYPE_INT, 800,
"height", G_TYPE_INT, 480,
"framerate", GST_TYPE_FRACTION, 25,
1, NULL);
gst_app_src_set_caps(GST_APP_SRC(app->appsrc), video_caps);
/* go to playing and wait in a mainloop. */
gst_element_set_state ((GstElement*) app->pipeline, GST_STATE_PLAYING);
fprintf(stderr, "gst_element_set_state play\n");
/* this mainloop is stopped when we receive an error or EOS */
g_main_loop_run (app->loop);
fprintf(stderr, "g_main_loop_run called\n");
gst_element_set_state ((GstElement*) app->pipeline, GST_STATE_NULL);
fprintf(stderr, "gst_element_set_state GST_STATE_NULL\n");
/* free the file */
// g_mapped_file_unref (app->file);
gst_object_unref (bus);
g_main_loop_unref (app->loop);
return 0;
}
void populateApp(void *inBuf , size_t len) {
guint8 *_buffer = (guint8*) inBuf;
GstFlowReturn ret;
GstBuffer *buffer = gst_buffer_new();
GstCaps* video_caps = gst_caps_new_simple ("video/x-h264",
"width", G_TYPE_INT, 800,
"height", G_TYPE_INT, 480,
"framerate", GST_TYPE_FRACTION, 25,
1, NULL);
gst_buffer_set_caps(buffer, video_caps);
GST_BUFFER_DATA (buffer) = _buffer;
GST_BUFFER_SIZE (buffer) = len;
// g_signal_emit_by_name (app->appsrc, "push-buffer", buffer, &ret);
ret = gst_app_src_push_buffer(GST_APP_SRC(app->appsrc), buffer);
gst_buffer_unref (buffer);
}
As said, I am a total newbie at GStreamer so there's a lot of cut-and-paste code from the internet, but IMHO it should work.
Do you see any issues?
It's not clear how you are calling populateApp, but you need to call that repeatedly as you have data to push to your pipeline. This can be done in a separate thread from the one blocked by g_main_loop_run, or you can restructure your program to avoid using GMainLoop.

iOS CFSocket and C Socket

in iOS CFSocket the way handle callback function is as followed
void receiveData(CFSocketRef s,
CFSocketCallBackType type,
CFDataRef address,
const void *data,
void *info)
{
}
int main ()
{
CFSocketRef s = CFSocketCreate(NULL, PF_INET,
SOCK_STREAM, IPPROTO_TCP,
kCFSocketDataCallBack,
receiveData,
NULL);
struct sockaddr_in sin;
struct hostent *host;
host = gethostbyname("localhost");
memset(&sin, 0, sizeof(sin));
memcpy(&(sin.sin_addr), host->h_addr,host->h_length);
sin.sin_family = AF_INET;
sin.sin_port = htons(888);
CFDataRef address, data;
UInt8 message[] = "Hello world";
CFRunLoopSourceRef source;
address = CFDataCreate(NULL, (UInt8 *)&sin, sizeof(sin));
data = CFDataCreate(NULL, message, sizeof(message));
CFSocketConnectToAddress(s, address, 0);
CFSocketSendData(s, NULL, data, 0);
}
in CFSocket when we do a CFSocketCreate we put the callback function in the SocketCreate function.
But for C Code the Socket and read from Socket is as followed.
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
I don't how to implement the callback read function inside the C Code. The callback function would be implemented every time something come into the buffer.
As you noted BSD sockets is not callback based, you need to poll from read to receive new data. You can call this periodically on the main thread or create a custom thread for reading data repeatedly.
CFSocket wraps BSD sockets at a higher level. It has some nice features, I believe that it automatically handles threading, and sleeps the thread until data is received. Reimplemnenting these features would not be a trivial process.
Good resources:
http://beej.us/guide/bgnet/
BSD Sockets - How to use non-blocking sockets?
http://man7.org/linux/man-pages/man2/poll.2.html

Resources