Related
I'm trying to read the packed pattern data of an .XM module using FT2 clone to write some test data
the pseudo code for unpacking is,
dbyt = getbyte();
if (dbyt AND 0x80) {
if (dbyt AND 0x01) c_note = getbyte();
if (dbyt AND 0x02) c_inst = getbyte();
if (dbyt AND 0x04) c_vol = getbyte();
if (dbyt AND 0x08) c_effect = getbyte();
if (dbyt AND 0x10) c_param = getbyte();
} else {
c_note = dbyt;
current_row++;
}
here is my code.
#pragma pack(push,1)
struct XM_Header
{
char id[17];
char name[20];
char idx;
char trackername[20];
WORD tracker_revision;
DWORD header_size;
WORD song_length;
WORD restart_position;
WORD num_channels;
WORD num_pat;
WORD num_inst;
WORD flags;
WORD default_tempo;
WORD default_bpm;
char pat_order[256];
};
#pragma pack(pop)
XM_Header xm_header;
bool LoadXM(const char* filename)
{
int error;
FILE* filePtr;
unsigned int count;
HRESULT result;
// Open the .XM file in binary.
error = fopen_s(&filePtr, filename, "rb");
if (error != 0)
{
return false;
}
// Read in the wave file header.
count = fread(&xm_header, sizeof(xm_header), 1, filePtr);
if (count != 1)
{
// return false;
}
if (xm_header.idx != 0x1A)
{
return false;
}
// fseek(filePtr, xm_header.header_size, SEEK_SET);
count = fread(&pat_head_len, sizeof(pat_head_len), 1, filePtr);
count = fread(&pack_type, sizeof(pack_type), (size_t) 1, filePtr);
if (pack_type != 0)
{
// return false;
}
count = fread(&pat_len, sizeof(pat_len), 1, filePtr);
count = fread(&pack_datasize, sizeof(pack_datasize), 1, filePtr);
pack_datasize = pack_datasize * xm_header.num_channels;
unsigned char *pat_data = new unsigned char[pack_datasize];
count = fread(pat_data, (size_t) 1, (size_t) pack_datasize, filePtr);
int i = 0, j = 0;
pat_size = pat_len * xm_header.num_channels;
pat_note = new unsigned char[pat_size];
pat_inst = new unsigned char[pat_size];
pat_vol = new unsigned char[pat_size];
pat_effect = new unsigned char[pat_size];
pat_param = new unsigned char[pat_size];
while (i < pat_len)
{
unsigned char dbyt = *pat_data++;
if (dbyt & 0x80) {
if (dbyt & 0x01) pat_note[i] = *pat_data++;
if (dbyt & 0x02) pat_inst[i] = *pat_data++;
if (dbyt & 0x04) pat_vol[i] = *pat_data++;
if (dbyt & 0x08) pat_effect[i] = *pat_data++;
if (dbyt & 0x10) pat_param[i] = *pat_data++;
}
else {
pat_note[i] = dbyt;
pat_inst[i] = *pat_data++;
pat_vol[i] = *pat_data++;
pat_effect[i] = *pat_data++;
pat_param[i] = *pat_data++;
}
i++;
}
return true;
}
I'm reading in the notes but there are 205 values in between the notes every 8 bytes, I know there is source code available XMP on github. Any ideas? Is this normal for an .XM module.
This is the Specification.
https://gist.github.com/loveemu/737ace92f08b439a416adc829ae2aa76
I'm trying to program a class to control the MPU6050 with the Arduino Wire library but when I run the code in my Arduino mini it freezes after a few seconds.
There is the code of the library and a test sketch:
// Include Wire Library for I2C
#include <Wire.h>
enum MPU6050_filter {_256Hz, _188Hz, _98Hz, _42Hz, _20Hz, _10Hz, _5Hz};
enum MPU6050_gyro {_250dps, _500dps, _1000dps, _2000dps};
enum MPU6050_accel {_2g, _4g, _8g, _16Hz};
class MPU6050
{
public:
MPU6050 ();
bool start (bool AD0_value);
void goToSleep ();
void stopSleeping ();
void setFilterVal (MPU6050_filter filter_val);
void setGyroRange (MPU6050_gyro range);
void setAccelRange (MPU6050_accel range);
bool dataAvailable ();
void getLastGyroData (float& gx, float& gy, float& gz);
void getRawGyroData (int& gx, int& gy, int& gz);
private:
void writeRegister (byte address, byte data);
byte readRegister (byte address);
void readData (byte start_address, byte bytes, byte* data);
float convertGyroToDPS (int gyro);
bool AD0_val;
MPU6050_filter filter;
MPU6050_accel accel_range;
MPU6050_gyro gyro_range;
unsigned long last_read;
const unsigned long min_read_time = 1;
};
MPU6050::MPU6050 () : AD0_val(false),
filter(_256Hz),
accel_range(_2g),
gyro_range(_250dps) {}
bool MPU6050::start (bool AD0_value)
{
AD0_val = AD0_value;
// init sample rate div to 0 (max sample rate)
writeRegister(0x19, 0);
// activate FIFO for gyroscope data
writeRegister(0x23, 0x70);
// clear config setup register
writeRegister(0x6B, 0);
// setup the register
writeRegister(0x37, 0x10);
// set interrupt by data ready
writeRegister(0x38, 0x01);
}
void MPU6050::goToSleep ()
{
byte prev_data = readRegister(0x6B);
prev_data = (prev_data | 0x40);
writeRegister(0x6B, prev_data);
}
void MPU6050::stopSleeping ()
{
byte prev_data = readRegister(0x6B);
prev_data = (prev_data & 0xBF);
writeRegister(0x6B, prev_data);
}
void MPU6050::setFilterVal (MPU6050_filter filter_val)
{
int val;
if (filter_val == _256Hz) val = 0;
else if (filter_val == _188Hz) val = 1;
else if (filter_val == _98Hz) val = 2;
else if (filter_val == _42Hz) val = 3;
else if (filter_val == _20Hz) val = 4;
else if (filter_val == _10Hz) val = 5;
else val = 6;
byte data = readRegister(0x1A);
data = (data & 0xF8) | (val & 0x07);
writeRegister(0x1A, data);
filter = filter_val;
}
void MPU6050::setAccelRange (MPU6050_accel range)
{
byte value;
if (range == _2g) value = 0;
else if (range == _4g) value = 1;
else if (range == _8g) value = 2;
else value = 3;
byte reg_value = readRegister(0x1C);
reg_value = (reg_value & 0xE0) | (value << 3);
writeRegister(0x1C, reg_value);
accel_range = range;
}
void MPU6050::setGyroRange (MPU6050_gyro range)
{
byte value;
if (range == _250dps) value = 0;
else if (range == _500dps) value = 1;
else if (range == _1000dps) value = 2;
else value = 3;
byte reg_value = readRegister(0x1B);
reg_value = (reg_value & 0xE0) | (value << 3);
writeRegister(0x1B, reg_value);
gyro_range = range;
}
bool MPU6050::dataAvailable ()
{
return (readRegister(0x3A) & 0x01);
}
void MPU6050::getLastGyroData (float& gx, float& gy, float& gz)
{
int raw_x, raw_y, raw_z;
getRawGyroData(raw_x, raw_y, raw_z);
gx = convertGyroToDPS(raw_x);
gy = convertGyroToDPS(raw_y);
gz = convertGyroToDPS(raw_z);
}
void MPU6050::getRawGyroData (int& gx, int& gy, int& gz)
{
byte* data = new byte[6];
readData(0x43, 6, data);
gx = data[0] << 8 | data[1];
gy = data[2] << 8 | data[3];
gz = data[4] << 8 | data[5];
delete data;
}
void MPU6050::writeRegister (byte address, byte data)
{
Wire.beginTransmission(0x68 + AD0_val);
Wire.write(address);
Wire.write(data);
Wire.endTransmission();
}
byte MPU6050::readRegister (byte address)
{
byte data_buff = 0x00;
Wire.beginTransmission(byte(0x68 + AD0_val));
//Send the requested starting register
Wire.write(address);
//End the transmission
Wire.endTransmission(false);
//Request 14 bytes from the MPU-6050
Wire.requestFrom(byte(0x68 + AD0_val), byte(0x01), byte(true));
unsigned long initial_time = millis();
//Wait until all the bytes are received
while(Wire.available() == 0 and millis() < initial_time + 5);
if (millis() < initial_time + 5)
{
// read the data
data_buff = Wire.read();
}
// end the transmission
Wire.endTransmission();
return data_buff;
}
void MPU6050::readData (byte start_address, byte bytes, byte* data)
{
Wire.beginTransmission(byte(0x68 + AD0_val));
//Send the requested starting register
Wire.write(start_address);
//End the transmission
Wire.endTransmission(false);
//Request 14 bytes from the MPU-6050
Wire.requestFrom(byte(0x68 + AD0_val), bytes, byte(true));
//Wait until all the bytes are received
while(Wire.available() < bytes);
for (int i = 0; i < bytes; i++)
data[i] = Wire.read();
Wire.endTransmission();
}
float MPU6050::convertGyroToDPS (int gyro)
{
if (gyro_range == _250dps) return float(gyro)/131.0;
else if (gyro_range == _500dps) return float(gyro)/65.5;
else if (gyro_range == _1000dps) return float(gyro)/32.8;
else return float(gyro)/16.4;
}
#define SHOW_EACH 50
MPU6050 chip;
unsigned long last_shown = 0;
unsigned this_fps = 0;
unsigned last_fps = 0;
unsigned last_time = 0;
unsigned total_fps = 0;
float g_x, g_y, g_z;
void setup()
{
Serial.begin(115200);
Serial.println("--------");
chip.setFilterVal(_256Hz);
chip.setGyroRange(_250dps);
chip.start(false);
}
void loop()
{
if (chip.dataAvailable())
chip.getLastGyroData(g_x, g_y, g_z);
++this_fps;
++total_fps;
if (millis()/1000 != last_time)
{
last_time = millis()/1000;
last_fps = this_fps;
this_fps = 0;
}
if (millis() - last_shown >= SHOW_EACH)
{
last_shown = millis();
Serial.print(g_x);
Serial.print(" ");
Serial.print(g_y);
Serial.print(" ");
Serial.print(g_y);
Serial.print(" ");
Serial.print(last_fps);
Serial.print(" ");
Serial.println(total_fps);
}
}
Some testing with Serial.println points to the function requestFrom from the Wire library. What can be the cause?
Sorry that i write this as an answer, but I can't write comments yet.
1st. There are multiple requestFrom() calls in your code, so it would be better to specify where does the problem occure exactly (if you can).
2nd. Are you completely sure that, it's the requestFrom() where your code hang. In readData() there is a while() just after requestFrom(). Maybe it hangs there, as the other device don't send enough bytes (for some reasons).
Anyway this might help a litle (link), here they recommend to always check the return value of endTransmission().
I'm making a small client/server based game, on linux in c/c++ and I need to send the player turn to the server.
Here is my problem.
I want to send two integers to the server and sometimes it works perfectly, but sometimes the server receives both integer in the first recv() and its stuck.
I know that the best way is to package the messages.
The problem is I don't know how the syntax should look like.
In theory--> the player input would be like an int column = 4 and a second int row = 1 and I package the message as 4|1 or something like this. Then I send from client to server and encode it on the server.
An example would be great or maybe some advice how stuff like this is handled probably.
I'm still very new to socket programming.
Here is how my function looks like:
Client:
#define BUFFER 512
void send_turn_to_server(int sock, int row, int column)
{
// sends row to server from player turn
char char_row[BUFFER];
sprintf(char_row, "%d", row);
char *message_from_client = char_row;
int len, bytes_sent_row;
len = strlen(message_from_client);
if (sendall(sock, message_from_client, &len) == -1)
{
perror("sendall");
printf("We only sent %d bytes because of the error!\n", len);
}
char char_column[BUFFER];
int bytes_sent_column;
//sends column from player turn
//sprintf converts the int to char
sprintf(char_column, "%d", column);
char *column_from_client = char_column;
len = strlen(column_from_client);
if (sendall(sock, column_from_client, &len) == -1)
{
perror("sendall");
printf("We only sent %d bytes because of the error!\n", len);
}
cout << "send_turn_to_server_complete" << endl;
}
Here I use a function from Beej's Guide to Network Programming, so I can be sure the whole buffer is sent.
Client:
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while (total < *len)
{
n = send(s, buf + total, bytesleft, 0);
if (n == -1)
{
break;
}
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n == -1 ? -1 : 0; // return -1 on failure, 0 on success
}
Server:
int receive_player_turn(int sock, int &int_row, int &int_column)
{
int byte_count;
char buf[BUFFER];
byte_count = recv(sock, buf, sizeof buf, 0);
cout << "The row from player: " << buf << endl;
//The C library function int atoi(const char *str) converts the string argument str to an integer (type int).
int_row = atoi(buf);
//cleans the buffer
bzero(buf, sizeof(buf));
byte_count = recv(sock, buf, sizeof buf, 0);
cout << buf << endl;
cout << "The column from player: " << buf << endl;
//converts the char string to an int
int_column = atoi(buf);
cout << endl
<< "receive player turn worked" << endl
<< "players turn was in the row " << int_row << " and in the column " << int_column + 1 << endl;
return int_row, int_column;
}
output correct from server:
Player connected: SchleichsSalaticus
The row from player: 7
4
The column from player: 4
receive player turn worked
players turn was in the row 7 and in the column 5
7 4
output wrong from server:
Player connected: SchleichsSalaticus
The row from player: 74
The issue is that TCP is a continuous stream, with no concept of the start or end of a ”message” because it is not message-based.
Most times, people use a very simple ”framing protocol” whereby you always send a 4-byte header on every transfer which tells the recipient how many bytes to read, then you send that many bytes as your message.
Use htonl() to send the 4-byte header in network byte order then you will be interoperable. There is a very similar example here.
One possible solution could be defining a format for the message that client send to server. For example you could define a protocol as follow:
[4 bytes length of your message][2 bytes for first player][2 bytes for second one] and in server side you should at first in rcv function get 4 bytes and extract the length of the arrived message and based on the receiving length(L) call again the rcv function with size L after that you should parse received messaged and extract the turn of each players.
If all your messages are expected to be of same length, then you do not need a message header. Something like that given below should work fine. In general you should be prepared to receive less or more than your expected message, as well as for one message to be split across many receives.
Also, I would recommend one function that receives bytes making no assumption about what they mean, and another that interprets them. Then the first one can be applied more broadly.
Treat the following only as pseudo code. not tested.
// use a buffer length double of MESSAGE_LENGTH.
static int offset = 0; // not thread safe.
// loop to receive a message.
while(offset < MESSAGE_LENGTH) {
byte_count = recv(sock, &buf[offset], (sizeof(buf)-offset), 0);
if(byte_count > 0) {
offset += byte_count;
}
else {
// add error handling here. close socket.
break out of loop
}
}
// process buf here, but do not clear it.
// received message always starts at buf[0].
if(no receive error above) {
process_received_message(buf); //
}
// move part of next message (if any) to start of buffer.
if(offset > MESSAGE_LENGTH) {
// copy the start of next message to start of buffer.
// and remember the new offset to avoid overwriting them.
char* pSrc = &buf[MESSAGE_LENGTH];
char* pSrcEnd = &buf[offset];
char* pDest = buf;
while(pSrc < pSrcEnd){
*pDest++ = *pSrc++;
} //or memcpy.
offset -= MESSAGE_LENGTH;
}
else {
offset = 0;
}
On many hardware architectures, integers and other types have alignment requirements. The compiler normally takes care of this, but when in a buffer, unaligned accesses can be an issue. Furthermore, the server and the client might not use the same byte order.
Here is a set of inline helper functions you can use to pack and unpack integer types to/from a buffer:
/* SPDX-License-Identifier: CC0-1.0 */
#ifndef PACKING_H
#define PACKING_H
#include <stdint.h>
/* Packing and unpacking unsigned and signed integers in
little-endian byte order.
Works on all architectures and OSes when compiled
using a standards-conforming C implementation, C99 or later.
*/
static inline void pack_u8(unsigned char *dst, uint8_t val)
{
dst[0] = val & 255;
}
static inline void pack_u16(unsigned char *dst, uint16_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
}
static inline void pack_u24(unsigned char *dst, uint32_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
dst[2] = (val >> 16) & 255;
}
static inline void pack_u32(unsigned char *dst, uint32_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
dst[2] = (val >> 16) & 255;
dst[3] = (val >> 24) & 255;
}
static inline void pack_u40(unsigned char *dst, uint64_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
dst[2] = (val >> 16) & 255;
dst[3] = (val >> 24) & 255;
dst[4] = (val >> 32) & 255;
}
static inline void pack_u48(unsigned char *dst, uint64_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
dst[2] = (val >> 16) & 255;
dst[3] = (val >> 24) & 255;
dst[4] = (val >> 32) & 255;
dst[5] = (val >> 40) & 255;
}
static inline void pack_u56(unsigned char *dst, uint64_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
dst[2] = (val >> 16) & 255;
dst[3] = (val >> 24) & 255;
dst[4] = (val >> 32) & 255;
dst[5] = (val >> 40) & 255;
dst[6] = (val >> 48) & 255;
}
static inline void pack_u64(unsigned char *dst, uint64_t val)
{
dst[0] = val & 255;
dst[1] = (val >> 8) & 255;
dst[2] = (val >> 16) & 255;
dst[3] = (val >> 24) & 255;
dst[4] = (val >> 32) & 255;
dst[5] = (val >> 40) & 255;
dst[6] = (val >> 48) & 255;
dst[7] = (val >> 56) & 255;
}
static inline void pack_i8(unsigned char *dst, int8_t val)
{
pack_u8((uint8_t)val);
}
static inline void pack_i16(unsigned char *dst, int16_t val)
{
pack_u16((uint16_t)val);
}
static inline void pack_i24(unsigned char *dst, int32_t val)
{
pack_u24((uint32_t)val);
}
static inline void pack_i32(unsigned char *dst, int32_t val)
{
pack_u32((uint32_t)val);
}
static inline void pack_i40(unsigned char *dst, int64_t val)
{
pack_u40((uint64_t)val);
}
static inline void pack_i48(unsigned char *dst, int64_t val)
{
pack_u48((uint64_t)val);
}
static inline void pack_i56(unsigned char *dst, int64_t val)
{
pack_u56((uint64_t)val);
}
static inline void pack_i64(unsigned char *dst, int64_t val)
{
pack_u64((uint64_t)val);
}
static inline uint8_t unpack_u8(const unsigned char *src)
{
return (uint_fast8_t)(src[0] & 255);
}
static inline uint16_t unpack_u16(const unsigned char *src)
{
return (uint_fast16_t)(src[0] & 255)
| ((uint_fast16_t)(src[1] & 255) << 8);
}
static inline uint32_t unpack_u24(const unsigned char *src)
{
return (uint_fast32_t)(src[0] & 255)
| ((uint_fast32_t)(src[1] & 255) << 8)
| ((uint_fast32_t)(src[2] & 255) << 16);
}
static inline uint32_t unpack_u32(const unsigned char *src)
{
return (uint_fast32_t)(src[0] & 255)
| ((uint_fast32_t)(src[1] & 255) << 8)
| ((uint_fast32_t)(src[2] & 255) << 16)
| ((uint_fast32_t)(src[3] & 255) << 24);
}
static inline uint64_t unpack_u40(const unsigned char *src)
{
return (uint_fast64_t)(src[0] & 255)
| ((uint_fast64_t)(src[1] & 255) << 8)
| ((uint_fast64_t)(src[2] & 255) << 16)
| ((uint_fast64_t)(src[3] & 255) << 24)
| ((uint_fast64_t)(src[4] & 255) << 32);
}
static inline uint64_t unpack_u48(const unsigned char *src)
{
return (uint_fast64_t)(src[0] & 255)
| ((uint_fast64_t)(src[1] & 255) << 8)
| ((uint_fast64_t)(src[2] & 255) << 16)
| ((uint_fast64_t)(src[3] & 255) << 24)
| ((uint_fast64_t)(src[4] & 255) << 32)
| ((uint_fast64_t)(src[5] & 255) << 40);
}
static inline uint64_t unpack_u56(const unsigned char *src)
{
return (uint_fast64_t)(src[0] & 255)
| ((uint_fast64_t)(src[1] & 255) << 8)
| ((uint_fast64_t)(src[2] & 255) << 16)
| ((uint_fast64_t)(src[3] & 255) << 24)
| ((uint_fast64_t)(src[4] & 255) << 32)
| ((uint_fast64_t)(src[5] & 255) << 40)
| ((uint_fast64_t)(src[6] & 255) << 48);
}
static inline uint64_t unpack_u64(const unsigned char *src)
{
return (uint_fast64_t)(src[0] & 255)
| ((uint_fast64_t)(src[1] & 255) << 8)
| ((uint_fast64_t)(src[2] & 255) << 16)
| ((uint_fast64_t)(src[3] & 255) << 24)
| ((uint_fast64_t)(src[4] & 255) << 32)
| ((uint_fast64_t)(src[5] & 255) << 40)
| ((uint_fast64_t)(src[6] & 255) << 48)
| ((uint_fast64_t)(src[7] & 255) << 56);
}
static inline int8_t unpack_i8(const unsigned char *src)
{
return (int8_t)(src[0] & 255);
}
static inline int16_t unpack_i16(const unsigned char *src)
{
return (int16_t)unpack_u16(src);
}
static inline int32_t unpack_i24(const unsigned char *src)
{
uint_fast32_t u = unpack_u24(src);
/* Sign extend to 32 bits */
if (u & 0x800000)
u |= 0xFF000000;
return (int32_t)u;
}
static inline int32_t unpack_i32(const unsigned char *src)
{
return (int32_t)unpack_u32(src);
}
static inline int64_t unpack_i40(const unsigned char *src)
{
uint_fast64_t u = unpack_u40(src);
/* Sign extend to 64 bits */
if (u & UINT64_C(0x0000008000000000))
u |= UINT64_C(0xFFFFFF0000000000);
return (int64_t)u;
}
static inline int64_t unpack_i48(const unsigned char *src)
{
uint_fast64_t u = unpack_i48(src);
/* Sign extend to 64 bits */
if (u & UINT64_C(0x0000800000000000))
u |= UINT64_C(0xFFFF000000000000);
return (int64_t)u;
}
static inline int64_t unpack_i56(const unsigned char *src)
{
uint_fast64_t u = unpack_u56(src);
/* Sign extend to 64 bits */
if (u & UINT64_C(0x0080000000000000))
u |= UINT64_C(0xFF00000000000000);
return (int64_t)u;
}
static inline int64_t unpack_i64(const unsigned char *src)
{
return (int64_t)unpack_u64(src);
}
#endif /* PACKING_H */
When packed, these values are in two's complement little-endian byte order.
pack_uN() and unpack_uN() work with unsigned integers from 0 to 2N-1, inclusive.
pack_iN() and unpack_iN() work with signed integers from -2N-1 to 2N-1-1, inclusive.
Let's consider a simple binary protocol, where each message starts with two bytes: first one the total length of this message, and the second one identifying the type of the message.
This has the nice feature that if something odd happens, it is always possible to resynchronize by sending at least 256 zeroes. Each zero is an invalid length for the message, so they should just be skipped by the receiver. You probably won't need this, but it may come in handy someday.
To receive a message of this form, we can use the following function:
/* Receive a single message.
'fd' is the socket descriptor, and
'msg' is a buffer of at least 255 chars.
Returns -1 with errno set if an error occurs,
or the message type (0 to 255, inclusive) if success.
*/
int recv_message(const int fd, unsigned char *msg)
{
ssize_t n;
msg[0] = 0;
msg[1] = 0;
/* Loop to skip zero bytes. */
do {
do {
n = read(fd, msg, 1);
} while (n == -1 && errno == EINTR);
if (n == -1) {
/* Error; errno already set. */
return -1;
} else
if (n == 0) {
/* Other end closed the socket. */
errno = EPIPE;
return -1;
} else
if (n != 1) {
errno = EIO;
return -1;
}
} while (msg[0] == 0);
/* Read the rest of the message. */
{
unsigned char *const end = msg + msg[0];
unsigned char *ptr = msg + 1;
while (ptr < end) {
n = read(fd, ptr, (size_t)(end - ptr));
if (n > 0) {
ptr += n;
} else
if (n == 0) {
/* Other end closed socket */
errno = EPIPE;
return -1;
} else
if (n != -1) {
errno = EIO;
return -1;
} else
if (errno != EINTR) {
/* Error; errno already set */
return -1;
}
}
}
/* Success, return message type. */
return msg[1];
}
In your own code, you can use the above like this:
unsigned char buffer[256];
switch(receive_message(fd, buffer)) {
case -1:
if (errno == EPIPE) {
/* The other end closed the connection */
} else {
/* Other error; see strerror(errno). */
}
break or return or abort;
case 0: /* Exit/cancel game */
break or return or abort;
case 4: /* Coordinate message */
int x = unpack_i16(buffer + 2);
int y = unpack_i16(buffer + 4);
/* x,y is the coordinate pair; do something */
break;
default:
/* Ignore all other message types */
}
where I randomly chose 0 as the abort-game message type, and 4 as the coordinate message type.
Instead of scattering such statements here and there in your client, put it in a function. You could also consider using a finite-state machine to represent the game state.
To send messages, you can use a helper function like
/* Send one or more messages; does not verify contents.
Returns 0 if success, -1 with errno set if an error occurs.
*/
int send_message(const int fd, const void *msg, const size_t len)
{
const unsigned char *const end = (const unsigned char *)msg + len;
const unsigned char *ptr = (const unsigned char *)msg;
ssize_t n;
while (ptr < end) {
n = write(fd, ptr, (size_t)(end - ptr));
if (n > 0) {
ptr += n;
} else
if (n != -1) {
/* C library bug, should not occur */
errno = EIO;
return -1;
} else
if (errno != EINTR) {
/* Other error */
return -1;
}
}
return 0;
}
so that sending an abort game (type 0) message would be
int send_abort_message(const int fd)
{
unsigned char buffer[2] = { 1, 0 };
return send_message(fd, buffer, 2);
}
and sending a coordinate (type 4) message would be e.g.
int send_coordinates(const int fd, const int x, const int y)
{
unsigned char buffer[2 + 2 + 2];
buffer[0] = 6; /* Length in bytes/chars */
buffer[1] = 4; /* Type */
pack_i16(buffer + 2, x);
pack_i16(buffer + 4, y);
return send_message(fd, buffer, 6);
}
If the game is not turn-based, you won't want to block in the sends or receives, like the above functions do.
Nonblocking I/O is the way to go. Essentially, you'll have something like
static int server_fd = -1;
static size_t send_size = 0;
static unsigned char *send_data = NULL;
static size_t send_next = 0; /* First unsent byte */
static size_t send_ends = 0; /* End of buffered data */
static size_t recv_size = 0;
static unsigned char *recv_data = NULL;
static size_t recv_next = 0; /* Start of next message */
static size_t recv_ends = 0; /* End of buffered data */
and you set the server_fd nonblocking using e.g. fcntl(server_fd, F_SETFL, O_NONBLOCK);.
A communicator function will try to send and receive as much data as possible. It will return 1 if it sent anything, 2 if it received anything, 3 if both, 0 if neither, and -1 if an error occurred:
int communicate(void) {
int retval = 0;
ssize_t n;
while (send_next < send_ends) {
n = write(server_fd, send_data + send_next, send_ends - send_next);
if (n > 0) {
send_next += n;
retval |= 1;
} else
if (n != -1) {
/* errno already set */
return -1;
} else
if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* Cannot send more without blocking */
break;
} else
if (errno != EINTR) {
/* Error, errno set */
return -1;
}
}
/* If send buffer became empty, reset it. */
if (send_next >= send_ends) {
send_next = 0;
send_ends = 0;
}
/* If receive buffer is empty, reset it. */
if (recv_next >= recv_ends) {
recv_next = 0;
recv_ends = 0;
}
/* Receive loop. */
while (1) {
/* Receive buffer full? */
if (recv_ends + 256 > recv_ends) {
/* First try to repack. */
if (recv_next > 0) {
memmove(recv_data, recv_data + recv_next, recv_ends - recv_next);
recv_ends -= recv_next;
recv_next = 0;
}
if (recv_ends + 256 > recv_ends) {
/* Allocate 16k more (256 messages!) */
size_t new_size = recv_size + 16384;
unsigned char *new_data;
new_data = realloc(recv_data, new_size);
if (!new_data) {
errno = ENOMEM;
return -1;
}
recv_data = new_data;
recv_size = new_size;
}
}
/* Try to receive incoming data. */
n = read(server_fd, recv_data + recv_ends, recv_size - recv_ends);
if (n > 0) {
recv_ends += n;
retval |= 2;
} else
if (n == 0) {
/* Other end closed the connection. */
errno = EPIPE;
return -1;
} else
if (n != -1) {
errno = EIO;
return -1;
} else
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else
if (errno != EINTR) {
return -1;
}
}
return retval;
}
When there is nothing to do, and you want to wait for a short while (some milliseconds), but interrupt the wait whenever more I/O can be done, use
/* Wait for max 'ms' milliseconds for communication to occur.
Returns 1 if data received, 2 if sent, 3 if both, 0 if neither
(having waited for 'ms' milliseconds), or -1 if an error occurs.
*/
int communicate_wait(int ms)
{
struct pollfd fds[1];
int retval;
/* Zero timeout is "forever", and we don't want that. */
if (ms < 1)
ms = 1;
/* We try communicating right now. */
retval = communicate();
if (retval)
return retval;
/* Poll until I/O possible. */
fds[0].fd = server_fd;
if (send_ends > send_next)
fds[0].events = POLLIN | POLLOUT;
else
fds[0].events = POLLIN;
fds[0].revents = 0;
poll(fds, 1, ms);
/* We retry I/O now. */
return communicate();
}
To process messages received thus far, you use a loop:
while (recv_next < recv_ends && recv_next + recv_data[recv_next] <= recv_ends) {
if (recv_data[recv_next] == 0) {
recv_next++;
continue;
}
/* recv_data[recv_next+0] is the length of the message,
recv_data[recv_next+1] is the type of the message. */
switch (recv_data[recv_next + 1]) {
case 4: /* Coordinate message */
if (recv_data[recv_next] >= 6) {
int x = unpack_i16(recv_data + recv_next + 2);
int y = unpack_i16(recv_data + recv_next + 4);
/* Do something with x and y ... */
}
break;
/* Handle other message types ... */
}
recv_next += recv_data[recv_next];
}
Then you recalculate game state, update the display, communicate some more, and repeat.
I just started learning C++ this year. Currently, I'm using four accelerometers to calculate human body movement for my school project. I tried to use multi-thread but the data outputs are unstable as such when I tried multiple times, some of the data would change. It does give correct output data sometimes. The output is saved to Microsoft Excel while printing on the screen simultaneously. However, When I tried the accelerometer separately, it seems to work just fine. The output would change only when I multi-thread them together. I can't seem to find what cause the output data to change periodically. I appreciate any help I could get. Pardon my grammatical mistakes for it is not my native language. Thank you =D
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <process.h>
#include <Windows.h>
#include "erslib.h"
struct SENSOR_DATA {
int ID_1, ID_2, ID_3,ID_4;
int y_1, y_2, y_3, y_4;
int z_1, z_2, z_3, z_4;
int x_1, x_2, x_3, x_4;
};
void Thread_0(void);
void Thread_1(void);
void Thread_2(void);
void Thread_3(void);
FILE *fp[4];
errno_t err[4];
int key = 0;
int MainLoopFlag = true;
SENSOR_DATA acc;
int main()
{
DWORD ThreadID_0;
DWORD ThreadID_1;
DWORD ThreadID_2;
DWORD ThreadID_3;
HANDLE Handle_0 = NULL;
HANDLE Handle_1 = NULL;
HANDLE Handle_2 = NULL;
HANDLE Handle_3 = NULL;
Handle_0 = CreateThread(0,0,(LPTHREAD_START_ROUTINE) Thread_0, 0, 0, &ThreadID_0);
Sleep(1000);
Handle_1 = CreateThread(0,0,(LPTHREAD_START_ROUTINE) Thread_1, 0, 0, &ThreadID_1);
Sleep(1000);
Handle_2 = CreateThread(0,0,(LPTHREAD_START_ROUTINE) Thread_2, 0, 0, &ThreadID_2);
Sleep(1000);
Handle_3 = CreateThread(0,0,(LPTHREAD_START_ROUTINE) Thread_3, 0, 0, &ThreadID_3);
Sleep(1000);
WaitForSingleObject(Thread_0, INFINITE);
WaitForSingleObject(Thread_1, INFINITE);
WaitForSingleObject(Thread_2, INFINITE);
WaitForSingleObject(Thread_3, INFINITE);
//////Print and Data Output//////
while(MainLoopFlag){
if(_kbhit()){
key = _getch(); //a key to start data saving//
if(key == 'a' && Save_flag==0){
printf("Preparing for saving...\n");
Sleep(5000);
printf("Saving start\n");
char * fname_0 = ("C:\\Users\\Desktop\\adam\\ID 1\\test02.csv");
err[0] = fopen_s(&fp[0], fname_0,"w+");
if (fp[0]==NULL) {
printf("%s File cannot be opened。\n",fname_0);
return -1;
}
char * fname_1 = ("C:\\Users\\Desktop\\adam\\ID 2\\test02.csv");
err[1] = fopen_s(&fp[1], fname_1,"w+");
if (fp[1]==NULL) {
printf("%s File cannot be opened。\n",fname_1);
return -1;
}
char * fname_2 = ("C:\\Users\\Desktop\\adam\\ID 3\\test02.csv");
err[2] = fopen_s(&fp[2], fname_2,"w+");
if (fp[2]==NULL) {
printf("%s File cannot be opened。\n",fname_2);
return -1;
}
char * fname_3 = ("C:\\Users\\Desktop\\adam\\ID 4\\test02.csv");
err[3] = fopen_s(&fp[3], fname_3,"w+");
if (fp[3]==NULL) {
printf("%s File cannot be opened。\n",fname_3);
return -1;
}
Save_flag=1;
while(MainLoopFlag && Save_flag==1){
printf("ID->%d, x->%d, y->%d, z->%d \n",acc.ID_1,acc.x_1,acc.y_1,acc.z_1);
fprintf(fp[0],"%d, %d, %d, %d \n",acc.ID_1,acc.x_1,acc.y_1,acc.z_1);
printf("ID->%d, x->%d, y->%d, z->%d \n",acc.ID_2,acc.x_2,acc.y_2,acc.z_2);
fprintf(fp[1],"%d, %d, %d, %d \n",acc.ID_2,acc.x_2,acc.y_2,acc.z_2);
printf("ID->%d, x->%d, y->%d, z->%d \n",acc.ID_3,acc.x_3,acc.y_3,acc.z_3);
fprintf(fp[2],"%d, %d, %d, %d \n",acc.ID_3,acc.x_3,acc.y_3,acc.z_3);
printf("ID->%d, x->%d, y->%d, z->%d \n",acc.ID_4,acc.x_4,acc.y_4,acc.z_4);
fprintf(fp[3],"%d, %d, %d, %d \n",acc.ID_4,acc.x_4,acc.y_4,acc.z_4);
if(_kbhit()){
key = _getch();
//s key to stop data saving
if(key == 's' && Save_flag==1){
printf("End Data saving\n");
Save_flag=0;
fclose(fp[0]);
fclose(fp[1]);
fclose(fp[2]);
fclose(fp[3]);
MainLoopFlag = false;}
}
}
}
}
}
// Close Handle
CloseHandle(Handle_0);
CloseHandle(Handle_1);
CloseHandle(Handle_2);
CloseHandle(Handle_3);
return 0;
}
//--------------------------------------------------------------------------
// Name: Thread_1(void)
//--------------------------------------------------------------------------
void Thread_1(void)
{
unsigned char buf[4096];
unsigned char buf_data[4096];
unsigned char bin_data[5];
//unsigned char buf_str[4096];
int i,j,n;
int n_cou;
int ComPort = 20;
int flag=0;
int temp_char_1[7];
ERS_Open(ComPort,4096,4096);
ERS_Config(ComPort,ERS_38400|ERS_NO|ERS_1|ERS_8);
//最初に取得するデータは異常なので捨てる
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
// 1となる位置を調べる
flag=0;
while(MainLoopFlag){
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
for(i=0;i<n;i++){
if((buf[i] & 0x80) == 0x80){
flag=1;
break;
}
}
if(flag==1)break;
Sleep(1);
}
// 1 となる位置から後ろをbuf_dataに入れる
n_cou = n - i;
for(j=0;j<n_cou;j++)
buf_data[j]=buf[i+j];
while(MainLoopFlag){
while(MainLoopFlag && n_cou<5){
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
for(i=0;i<n;i++)buf_data[n_cou+i]=buf[i];
n_cou=n_cou+n;
}
for(i=0;i<5;i++)bin_data[i]=buf_data[i];
temp_char_1[0] = (bin_data[0] & 0x38) >> 3; //ID
acc.ID_2 = (int)temp_char_1[0];
temp_char_1[1] = (bin_data[0] & 0x07) << 7; // x = 3bit
temp_char_1[2] = (bin_data[1] & 0x38) << 4; // y = 3bit
temp_char_1[3] = (bin_data[1] & 0x07) << 7; // z = 3bit
temp_char_1[4] = (bin_data[2] & 0x7F) | temp_char_1[1];
acc.x_2 = (int)temp_char_1[4];
temp_char_1[5] = (bin_data[3] & 0x7F) | temp_char_1[2];
acc.y_2 = (int)temp_char_1[5];
temp_char_1[6] = (bin_data[4] & 0x7F) | temp_char_1[3];
acc.z_2 = (int)temp_char_1[6];
for(i=5;i<n_cou;i++)buf_data[i-5]=buf_data[i];
n_cou=n_cou-5;
}
ERS_CloseAll();
}
//--------------------------------------------------------------------------
// Name: Thread_2(void)
//--------------------------------------------------------------------------
void Thread_2(void)
{
unsigned char buf[4096];
unsigned char buf_data[4096];
unsigned char bin_data[5];
//unsigned char buf_str[4096];
int i,j,n;
int n_cou;
int ComPort = 15;
int flag=0;
int temp_char_2[7];
ERS_Open(ComPort,4096,4096);
ERS_Config(ComPort,ERS_38400|ERS_NO|ERS_1|ERS_8);
//最初に取得するデータは異常なので捨てる
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
// 1となる位置を調べる
flag=0;
while(MainLoopFlag){
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
for(i=0;i<n;i++){
if((buf[i] & 0x80) == 0x80){
flag=1;
break;
}
}
if(flag==1)break;
Sleep(1);
}
// 1 となる位置から後ろをbuf_dataに入れる
n_cou = n - i;
for(j=0;j<n_cou;j++)
buf_data[j]=buf[i+j];
while(MainLoopFlag){
while(MainLoopFlag && n_cou<5){
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
for(i=0;i<n;i++)buf_data[n_cou+i]=buf[i];
n_cou=n_cou+n;
}
for(i=0;i<5;i++)bin_data[i]=buf_data[i];
temp_char_2[0] = (bin_data[0] & 0x38) >> 3; //ID
acc.ID_3 = (int)temp_char_2[0];
temp_char_2[1] = (bin_data[0] & 0x07) << 7; // x = 3bit
temp_char_2[2] = (bin_data[1] & 0x38) << 4; // y = 3bit
temp_char_2[3] = (bin_data[1] & 0x07) << 7; // z = 3bit
temp_char_2[4] = (bin_data[2] & 0x7F) | temp_char_2[1];
acc.x_3 = (int)temp_char_2[4];
temp_char_2[5] = (bin_data[3] & 0x7F) | temp_char_2[2];
acc.y_3 = (int)temp_char_2[5];
temp_char_2[6] = (bin_data[4] & 0x7F) | temp_char_2[3];
acc.z_3 = (int)temp_char_2[6];
for(i=5;i<n_cou;i++)buf_data[i-5]=buf_data[i];
n_cou=n_cou-5;
}
ERS_CloseAll();
}
//--------------------------------------------------------------------------
// Name: Thread_3(void)
//--------------------------------------------------------------------------
void Thread_3(void)
{
unsigned char buf[4096];
unsigned char buf_data[4096];
unsigned char bin_data[5];
//unsigned char buf_str[4096];
int i,j,n;
int n_cou;
int ComPort = 3;
int flag=0;
int temp_char_3[7];
ERS_Open(ComPort,4096,4096);
ERS_Config(ComPort,ERS_38400|ERS_NO|ERS_1|ERS_8);
//最初に取得するデータは異常なので捨てる
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
// 1となる位置を調べる
flag=0;
while(MainLoopFlag){
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
for(i=0;i<n;i++){
if((buf[i] & 0x80) == 0x80){
flag=1;
break;
}
}
if(flag==1)break;
Sleep(1);
}
// 1 となる位置から後ろをbuf_dataに入れる
n_cou = n - i;
for(j=0;j<n_cou;j++)
buf_data[j]=buf[i+j];
//for(i=0;i<n_cou;i++)printf("%x ",buf_data[i]);
//printf("\n");
while(MainLoopFlag){
while(MainLoopFlag && n_cou<5){
n=ERS_CheckRecv(ComPort);
ERS_Recv(ComPort,buf,n);
for(i=0;i<n;i++)buf_data[n_cou+i]=buf[i];
n_cou=n_cou+n;
}
for(i=0;i<5;i++)bin_data[i]=buf_data[i];
//for(i=0;i<5;i++)printf("%x ",bin_data[i]);
//printf("\n");
temp_char_3[0] = (bin_data[0] & 0x38) >> 3; //ID
acc.ID_4 = (int)temp_char_3[0];
temp_char_3[1] = (bin_data[0] & 0x07) << 7; // x = 3bit
temp_char_3[2] = (bin_data[1] & 0x38) << 4; // y = 3bit
temp_char_3[3] = (bin_data[1] & 0x07) << 7; // z = 3bit
temp_char_3[4] = (bin_data[2] & 0x7F) | temp_char_3[1];
acc.x_4 = (int)temp_char_3[4];
temp_char_3[5] = (bin_data[3] & 0x7F) | temp_char_3[2];
acc.y_4 = (int)temp_char_3[5];
temp_char_3[6] = (bin_data[4] & 0x7F) | temp_char_3[3];
acc.z_4 = (int)temp_char_3[6];
for(i=5;i<n_cou;i++)buf_data[i-5]=buf_data[i];
n_cou=n_cou-5;
}
ERS_CloseAll();
}
Correct data :
(Example)
ID->1, x->47, y->147, z->298
ID->2, x->298, y->25, z->147
ID->3, x->47, y->147, z->298
ID->4, x->213, y->123, z->43
ID->1, x->49, y->152, z->222
ID->2, x->256, y->30, z->155
ID->3, x->47, y->147, z->298
ID->4, x->221, y->132, z->54
incorrect data:
ID->1, x->905, y->179, z->20
ID->6, x->47, y->147, z->298
ID->0, x->0, y->0, z->0
ID->4, x->1010, y->56, z->23
ID->1, x->905, y->179, z->20
ID->6, x->47, y->147, z->298
ID->0, x->0, y->0, z->0
ID->4, x->1010, y->56, z->23
Basically the ID shouldn't change while the x, y and z would as you move the accelerometer.
SendARP is not setting my mac array, so likewise when I try to convert the mac array to BYTE to convert it to human readable, it also gets random characters in it. also the memset does not seem to make MacAddr 0!
std::wstring GetMacAddress(IPAddr destip)
{
DWORD ret;
ULONG MacAddr[2] = {0}; //initialize instead of memset
ULONG PhyAddrLen = 6; /* default to length of six bytes */
unsigned char mac[6];
//memset(MacAddr, 0, sizeof(MacAddr)); //MacAddr doesn't get set to 0!
//Send an arp packet
ret = SendARP(destip , 0, MacAddr , &PhyAddrLen); //MacAddr stays
//Prepare the mac address
if (ret == NO_ERROR)
{
BYTE *bMacAddr = (BYTE *) & MacAddr;
if(PhyAddrLen)
{
for (int i = 0; i < (int) PhyAddrLen; i++)
{
mac[i] = (char)bMacAddr[i];
}
}
}
}
I have tried numerous ways to get MacAddr to get set by the SendARP function, but it doesn't seem to work and it doesn't return an error.
Casting to char does not convert to a textual representation. If you want to convert to a textual representation one option is to use std::wstringstream
#include <sstream>
#include <string>
#include <iomanip>
std::wstring GetMacAddress(IPAddr destip)
{
// ... snip ...
std::wstringstream out;
for (int i = 0; i < (int) PhyAddrLen; i++)
{
out << std::setw(2) << std::setfill(L'0') << bMacAddr[i];
}
return out.str();
}
Try this:
static const wchar_t *HexChars = L"0123456789ABCDEF";
std::wstring GetMacAddress(IPAddr destip)
{
DWORD ret;
BYTE MacAddr[sizeof(ULONG)*2];
ULONG PhyAddrLen = sizeof(MacAddr);
std::wstring MacAddrStr;
ret = SendARP(destip, 0, (PULONG)MacAddr, &PhyAddrLen);
if ((ret == NO_ERROR) && (PhyAddrLen != 0))
{
MacAddrStr.resize((PhyAddrLen * 2) + (PhyAddrLen-1));
MacAddrStr[0] = HexChars[(MacAddr[0] & 0xF0) >> 4];
MacAddrStr[1] = HexChars[MacAddr[0] & 0x0F];
for (ULONG i = 1, j = 2; i < PhyAddrLen; ++i, j += 3)
{
MacAddrStr[j+0] = L':';
MacAddrStr[j+1] = HexChars[(MacAddr[i] & 0xF0) >> 4];
MacAddrStr[j+2] = HexChars[MacAddr[i] & 0x0F];
}
}
return MacAddrStr;
}