Scope of variables in C++ - c++

for the sake of overview, I wanted to outsource a few functions in another file.
Therefore I created a corresponding cpp and h file and put the funtions in there:
#include <routines.h>
void splash()
{
oled.startScreen();
oled.clear();
oled.drawImage(start_logo, 0, 0, 128, 8);
}
void prepareDisplay(){
unsigned int i,k;
unsigned char ch[5];
oled.clear();
oled.startScreen();
oled.cursorTo(0,0);
oled.printString( "ATTiny");
}
Problem is that those functions use variables (oled, start_logo) from the main file which leads to them being out of scope.
Main.cpp file:
#include <Arduino.h>
#include "SSD1306_minimal.h"
#include <EEPROM.h>
#include <routines.h>
//eeprom adresses:
byte calibratedAddress = 0;
//global variables:
bool isCalibrated;
//pin definitions:
const byte led = PA5;
SSD1306_Mini oled;
const unsigned char start_logo [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ongoing...
};
void setup(){
oled.init(0x3c);
oled.clear();
delay(1000);
splash();
delay(8000);
oled.clear();
}
void loop() {
}
Is it somehow possible to "hand over" the variables to the outsourced functions and if yes, how?
Thanks in advance for your help!

There's many ways to approach this. One easy way is to pass the needed varaible as an argument into the functions that need it.
// Pass the values needed as arguments
void splash(byte oled, unsigned char* start_logo)
{
oled.startScreen();
oled.clear();
oled.drawImage(start_logo, 0, 0, 128, 8);
}
Another way is to keep the functions as is and declare the variables in the new cpp file
// extern says that this variable is not defined .cpp file
// It's defined in another file
extern SSD1306_Mini oled;
// static in this context makes this variable only visible to this .cpp file
// extern in another file can't get this
static const unsigned char start_logo[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // more
};
void splash()
{
oled.startScreen();
oled.clear();
oled.drawImage(start_logo, 0, 0, 128, 8);
}
void prepareDisplay(){
unsigned int i,k;
unsigned char ch[5];
oled.clear();
oled.startScreen();
oled.cursorTo(0,0);
oled.printString( "ATTiny");
}

Related

ESP32 e-Paper Image: convert from unsigned int to char array

Problem:
I am printing unsigned char array to display an image on a 7.5" waveshare e-Paper display using ESP32 with the following function:
Paint_DrawImage(const unsigned char *image_buffer, UWORD xStart, UWORD yStart, UWORD W_Image, UWORD H_Image)
That function prints an image to an e-paper display image where you also define the starting pixels (xStart, yStart) and the image size in pixels (W_Image, H_Image).
I have the code working with a sample unsigned char array below:
const unsigned char gImage_7in5_V2_b[2056] = { /* 0X00,0X01,0X20,0X03,0XE0,0X01, */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
.... not showing the whole array to save space};
There are some images that will save me a lot of time that are already converted into a similar format which is as an unsigned int with the example below:
const unsigned int icon64_50n[132]= {
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x03000000,0x000000E0,0x1F000000,0x000000E0,0x7F000000,0x000000E0,
.... not showing the whole array to save space};
I have tried defining the array as an unsigned char but that didn't work and was really slow uploading to the ESP32 with lots of warnings.
Question:
Is this considered a byte array? I am new to this data type and need guidance on how/what to search for here.
How do I convert the unsigned int array to unsigned char?

How to pass and save a 2D array to an object using the constructor

There are a lot of solutions available for passing 2D arrays to an function, but I can not figure out how to assign that array to my object in the constructor. Any help would be appreciated.
I have an array of bytes:
int demo1_rows = 9;
int demo1_id[9] = { 0x0A1, 0x0A2, 0x0A0, 0x0A1, 0x0A2, 0x0A0, 0x0A1, 0x0A2, 0x0A0 };
uint8_t demo1[9][8] = {
{0x00, 0x00, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3},
{0x00, 0x00, 0x00, 0xB9, 0x00, 0xB9, 0x00, 0xB9},
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0xA5, 0x00, 0xA5, 0x00, 0xA5},
{0x00, 0x00, 0x00, 0xAF, 0x00, 0xAF, 0x00, 0xAF},
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0xB4, 0x00, 0xB4, 0x00, 0xB4},
{0x00, 0x00, 0x00, 0xB4, 0x00, 0xB4, 0x00, 0xB4},
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
};
My object:
Program Demo1(demo1, demo1_id, demo1_size);
My Class:
class Program
{
private:
uint8_t **program;
int *id;
int arraySize;
public:
Program(uint8_t func[][8], int new_id[], int size) {
program = func;
id = new_id;
arraySize = size;
}
}
There is an error when trying to assign func to program.
If you want to fix your current code, with minimal changes, and store the multidimentional array as a reference, you can do this:
typedef the array type, and store it as a reference. Then use the member initializer list in the constructor to take the reference and assign it. This will be similar to storing the pointer to the entire array.
#include <stdint.h>
int demo1_rows = 9;
int demo1_id[9] = { 0x0A1, 0x0A2, 0x0A0, 0x0A1, 0x0A2, 0x0A0, 0x0A1, 0x0A2, 0x0A0 };
uint8_t demo1[9][8] = {
{0x00, 0x00, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3},
{0x00, 0x00, 0x00, 0xB9, 0x00, 0xB9, 0x00, 0xB9},
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0xA5, 0x00, 0xA5, 0x00, 0xA5},
{0x00, 0x00, 0x00, 0xAF, 0x00, 0xAF, 0x00, 0xAF},
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0xB4, 0x00, 0xB4, 0x00, 0xB4},
{0x00, 0x00, 0x00, 0xB4, 0x00, 0xB4, 0x00, 0xB4},
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
};
typedef uint8_t MyArray[9][8];
class Program
{
private:
MyArray& program;
int* id;
int arraySize;
public:
Program(MyArray& func, int new_id[], int size)
: program (func)
{
id = new_id;
arraySize = size;
// you can now access program[3][3] etc
}
};
int main()
{
Program p(demo1, demo1_id, demo1_rows);
return 0;
}

In C++, I am trying to create a valid .bmp output file

I am trying to replicate a bmp found here: https://en.wikipedia.org/wiki/BMP_file_format (its the 2x2 one). Whenever I try and open it in paint or photoviewer or whatever it says it isn't supported. I'm not sure what I am doing wrong here. I have gone over the hex values several times and everything (as far as I can tell) looks identical. Help?
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ofstream bitmap;
unsigned char bm_header[14] =
/*BM*/ { 0x4D, 0x42,
/*70 bytes*/ 0x00, 0x00, 0x00, 0x46,
/*Unused */ 0x00, 0x00, 0x00, 0x00,
/* 54 bytes */ 0x00, 0x00, 0x00, 0x36 };
unsigned char dib_header[40] =
/*40 bytes*/ { 0x00, 0x00, 0x00, 0x28,
/*2 pixels wide*/ 0x00, 0x00, 0x00, 0x02,
/*2 pixels tall*/ 0x00, 0x00, 0x00, 0x02,
/*1 plane */ 0x00, 0x01,
/*24 bits */ 0x00, 0x18,
/*0 */ 0x00, 0x00, 0x00, 0x00,
/*16 bytes */ 0x00, 0x00, 0x00, 0x10,
/*2835 p/m wide*/ 0x00, 0x00, 0x0B, 0x13,
/*2835 p/m tall*/ 0x00, 0x00, 0x0B, 0x13,
/*0 colors*/ 0x00, 0x00, 0x00, 0x00,
/*0 import. colors*/0x00, 0x00, 0x00, 0x00 };
unsigned char pixel_header[16] =
{0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF,
0x00, 0x00,
0x00, 0x00, 0xFF,
0x00, 0xFF, 0x00,
0x00, 0x00 };
bitmap.open("mandelbrot_1.bmp", ios::out | ios::binary);
for(int i = 0; i < 14; i++) {
bitmap << bm_header[i];
}
for(int i = 0; i < 40; i++) {
bitmap << dib_header[i];
}
for(int i = 0; i < 16; i++) {
bitmap << pixel_header[i];
}
cout << "success!" << endl;
bitmap.close();
return 0;
}
Each field in bm_header and dib_header is reversed from what it should be. The values 0x4d, 0x42 spell out "MB", not "BM." The sequence 0x00, 0x00, 0x00, 0x46 is interpreted as 0x46000000 bytes, not 0x46 bytes. In general the bytes in the Wikipedia table are listed in the order that they should go into the file.
Go on YouTube and search for Handmade Hero Bitmap, or go on Handmade Hero's channel and watch episodes from 36 to 39.
Casey (the author) goes over literally everything you need to know in theory and in practice down to endianness quirks and struct tight packing.
Those episodes are easy enough to consume on their own even if you have no interest in the series or haven't watched the previous episodes.
I'd suggest you do an online search for BITMAPINFOHEADER. That will give you a structure you can use instead of manipulating bytes directly.

C# getting info from hexadecimal data

I have this hexadecimal data:
byte[] data = new Byte[] {
0xC1, 0x3A, 0x00, 0x01, 0x5D, 0xDA, 0x47, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0x12, 0x00, 0x00, 0x00
};
I have C++ struct:
struct SERVICE
{
unsigned char c;
unsigned char size;
unsigned char headcode;
unsigned char Type;
unsigned short Port;
char ServiceName[50];
unsigned short ServiceCode;
};
My question is: How to get from data ServiceName, Port and etc...?
Sorry for my bad english
Here is one way to do it:
struct SERVICE
{
public byte c;
public byte size;
public byte headcode;
public byte Type;
public ushort Port;
public string ServiceName;
public ushort ServiceCode;
};
string GetNullTerminatedString(byte[] data, Encoding encoding)
{
int index = Array.IndexOf(data, (byte)0);
if (index < 0)
{
Debug.WriteLine("No string terminator found.");
index = data.Length;
}
return encoding.GetString(data, 0, index);
}
SERVICE ByteArrayToService(byte[] array, Encoding encoding)
{
using (MemoryStream stream = new MemoryStream(array))
{
using (BinaryReader reader = new BinaryReader(stream))
{
SERVICE service = new SERVICE();
service.c = reader.ReadByte();
service.size = reader.ReadByte();
service.headcode = reader.ReadByte();
service.Type = reader.ReadByte();
service.Port = reader.ReadUInt16();
service.ServiceName = GetNullTerminatedString(reader.ReadBytes(50), encoding);
service.ServiceCode = reader.ReadUInt16();
return service;
}
}
}
void Main(string[] args)
{
byte[] data = new Byte[]
{
0xC1, 0x3A, 0x00, 0x01, 0x5D, 0xDA, 0x47, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0x12, 0x00, 0x00, 0x00
};
SERVICE s = ByteArrayToService(data, Encoding.Default);
}
This assumes, that the binary array uses the same Endianess as your architecture. If that is not the case you can use the EndianBinaryReader from the MiscUtil library.
Edit: this is also a nice solution, that avoids the reader altogether. You can't directly specify the encoding to use for the string however and the memory layout of the structure has to match the layout used in the byte array.
[StructLayout(LayoutKind.Sequential)]
struct SERVICE
{
public byte c;
public byte size;
public byte headcode;
public byte Type;
public ushort Port;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string ServiceName;
public ushort ServiceCode;
};
SERVICE ByteArrayToService(byte[] array)
{
GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
SERVICE service = (SERVICE)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SERVICE));
handle.Free();
return service;
}
First, Decide if your byte encoding is little or big endian. Then, unpack fields one by one (C example)
struct SERVICE s;
int i = 0;
s.c = data[i++];
s.size = data[i++];
s.headcode = data[i++];
s.Type = data[i++];
s.Port = data[i++] << 8 | data[i++]; /* This is where endian matters */
memcpy(s.ServiceName, &data[i], 50);
i += 50;
s.ServiceCode = data[i++] << 8 | data[i++];
NOTE: This is usually written as moving the data pointer instead of using "i" as an index, but I left it in this form for ease of moving to C#.
From the question, I could not find out how you want to achieve this but this is the C# structure.
You can define the structure as below
public struct Service
{
public byte C;
public byte Size;
public byte HeadCode;
public byte Type;
public UInt16 Port;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public byte[] values;
public UInt16 ServiceCode;
}

C++ Hex Parsing

I'm wondering how to convert a hex string to a human readable string (if that makes any sense) this would be my first real encounter with hex values so I'm still learning about them and how to manage them.
I have a program which is reading in data from a file which contains raw packet data (hex) and I need to parse this information so it's human readable.
An example of what I need to do is something like this site does http://home2.paulschou.net/tools/xlate/ where you can put in hex and have it converted to text.
Taken from the C++ String Toolkit Library (StrTk) library, the following should suffice. Note that out should point to a piece of memory half the size of as std::distance(begin,end), and that the values in the range of [begin,end) be 0-9A-F or 0-9a-f
inline bool convert_hex_to_bin(const unsigned char* begin,
const unsigned char* end,
unsigned char* out)
{
if (std::distance(begin,end) % 2)
return false;
static const std::size_t symbol_count = 256;
static const unsigned char hex_to_bin[symbol_count] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2F
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3F
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x40 - 0x47
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5F
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x60 - 0x67
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 - 0xA7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 - 0xAF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0 - 0xB7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 - 0xBF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 - 0xC7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 - 0xCF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 - 0xD7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 - 0xDF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 - 0xE7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 - 0xEF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 - 0xF7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0xF8 - 0xFF
};
const unsigned char* itr = begin;
while (end != itr)
{
(*out) = static_cast<unsigned char>(hex_to_bin[*(itr++)] << 4);
(*out) |= static_cast<unsigned char>(hex_to_bin[*(itr++)] );
++out;
}
return true;
}
The C++-ish way to get a string containing the hexadecimal representation of a given number is to use the hex modifier for streams, as in this example:
const int i = 0xdeadbeef;
cout << "0x" << hex << i << endl; // prints "0xdeadbeef"
You can use the same modifier on string streams in case you need to have the hexadecimal representation in a string variable:
const int i = 0xdeadc0de;
ostringstream stream;
stream << "0x" << hex << i;
const string s = stream.str(); // s now contains "0xdeadc0de"
UPDATE:
If your input data is given as a string containing the hexadecimal representation of the characters of a string, you will need to know the encoding of the input string in order to display it correctly. In the simplest case, the string is something like ASCII which maps one byte to one character. So in a given input "414243", every two characters ("41", "42", "43) map to an ASCII value (65, 66, 67), which map to a character ("A", "B", "C").
Here's how to that in C++:
const string hexData = "414243";
assert( hexData.size() % 2 == 0 );
ostringstream asciiStream;
istringstream hexDataStream( hexData );
vector<char> buf( 3 ); // two chars for the hex char, one for trailing zero
while ( hexDataStream.good() ) {
hexDataStream.get( &buf[0], buf.size() );
if ( hexDataStream.good() ) {
asciiStream << static_cast<char>( std::strtol( &buf[0], 0, 16 ) );
}
}
const string asciiData = asciiStream.str(); // asciiData == "ABC"
Using std::strtol from <cstdlib> makes this easy; if you insist on using a template class for this, use std::stringstream to perform the conversion of the single sub strings (like "41") to decimal values (65).
fprintf(file, "%h", thing);
Something along those lines?
Hex is a way of displaying binary data. It is not "raw data" as you say. If the raw data you have contains a string, you should be able to see the string (possibly among other garbage) when you output it to the screen.
Here's a loop to print the ASCII characters in a block of data. To get anything else, you will have to deal with its format.
char *binary_data[ BUFFER_SIZE ];
size_t len = BUFFER_SIZE;
len = get_a_packet( data, len ); // or however you get data
for ( char *text_ptr = binary_data; text_ptr != binary_data + len; ++ text_ptr ) {
if ( * text_ptr <= '~' && * text_ptr >= ' ' ) { // if it's ascii
cerr << * text_ptr; // print it out
}
}
cerr << endl;