Jump to content

Accessing hardware C/C++

TL;DR

Where’s a good resource in accessing hardware components with C or C++? 

 

Long

I was having trouble finding a nice standard library for network programming in C++. More or less, I’ve come to see nearly every compiler & OS has a different library assuming it even comes with one. 

I was hoping there’d be a method to access the network hardware directly & maybe just write the data to the components I want sent. 

It’d also be interesting to me if I could access other important pieces of hardware if I needed it. 

 

About why

I’ve been using & prototyping in C# however gritty graphics programming in C# is less convenient IMO. I’ve been considering switching to C++ for its neat features & vast native libraries. (Not many libraries in C++ are wrappers compared to C#)

I’m jealous of 8-bit guy & his ability to access everything he needs with Assembly. (Not that I’d like to do 15+ lines of code to just print something to the screen.)

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/
Share on other sites

Link to post
Share on other sites

It depends on what the application is running on top of.

 

If you're programming on bare metal, you literally read or write to the address that points to the hardware. This can be accomplished with pointers. So if a register or pin is at address 0xABCD and you want to write to it, this is all you have to do:

uint8_t *some_register = 0xABCD; 
/* The data type can be changed, but keep in mind that what the address points to accepts. Othrewise you may be writing to different things at once. */

*some_register = 1;

 

If you're programming for an OS, then it depends. I know POSIX style OSes can represent hardware I/O has a file or data stream, so you literally open a stream and read/write as normal. Outside of that, I don't know.

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12348857
Share on other sites

Link to post
Share on other sites

 

1 minute ago, Mira Yurizaki said:

So if a register or pin is at address 0xABCD and you want to write to it, this is all you have to do:

Ah so that’s how windows is in C/C++... I’d be interested in knowing how to compile for bare metal as most IDE I know of (visual studio, maybe GCC ETC) compile for OS applications or libraries. 

1 minute ago, Mira Yurizaki said:

If you're programming for an OS, then it depends. I know POSIX style OSes

How do I determine if my OS is POSIX? Is there a chart? Mostly targeting windows & Linux. Maybe Mac/OSX. 

1 minute ago, Mira Yurizaki said:

can represent hardware I/O has a file or data stream, so you literally open a stream and read/write as normal. Outside of that, I don't know.

Where can I find some information on where to stream the data? 

My textbooks on C++ don’t seem to talk about streaming data anywhere but to the console. 

I’ll triple check but I don’t think they’re that in depth. 

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12348874
Share on other sites

Link to post
Share on other sites

1 minute ago, fpo said:

Ah so that’s how windows is in C/C++... I’d be interested in knowing how to compile for bare metal as most IDE I know of (visual studio, maybe GCC ETC) compile for OS applications or libraries. 

It's not much different than an application built for an OS. It's probably more "pure" to your application since it doesn't need to include all of the things to hook into the OS.

 

Though you just need to find a compiler that can compile to and find a way to load it on the target.

1 minute ago, fpo said:

How do I determine if my OS is POSIX? Is there a chart? Mostly targeting windows & Linux. Maybe Mac/OSX. 

If it's UNIX or UNIX-like, then it can be safely assumed it's POSIX style. In fact, UNIX is just an OS certified to be compatible with the POSIX standard.

 

1 minute ago, fpo said:

Where can I find some information on where to stream the data? 

My textbooks on C++ don’t seem to talk about streaming data anywhere but to the console. 

I’ll triple check but I don’t think they’re that in depth. 

From what little I've worked with this, on POSIX systems the I/O stream is usually a file in /dev. So you would open this "file" and read or write to it. However, if you're working with an OS, you should probably just use a library since it'll be easier (an example: manipulating the GPIO pins on the Raspberry Pi)

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12348897
Share on other sites

Link to post
Share on other sites

The Windows API Index on MSDN is useful for this type of thing, at least on the Windows side.

That's if you really, really can't find a good library to do what you want to do. There are more than a few "gotchas" regarding the way that Windows and the Windows API works.

I have no experience working with any other OS this deeply, so I have nothing to offer there.

ENCRYPTION IS NOT A CRIME

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12348928
Share on other sites

Link to post
Share on other sites

As a programmer who always enjoys finding out how computers work behind the scenes, I'm happy to hear someone else is interested in this stuff, but I would strongly recommend that you get some experience working with standard networking libraries.  Not only will it get you some experience with networking and allow you to build applications faster, but it will also give you a better idea of the overall program flow, and why networking libraries are built the way they are, and let you know what works and what needs to be improved.

 

First, if you are going to work with low level code like this, it will be much easier in Linux.  Seriously, even if you have little to no experience with Linux, it will still be easier.

If for no other reason than there are way more resources for working with the hardware.

 

Now, to be honest and blunt about it, if you're goal is to write seriously low level code, as in f--k the levels of abstraction that make it easier, give me all the power; you're kinda S.O.L.  Not because it's not doable, but because little of the hardware is the same.  That's the whole point of device drivers, to provide a standardized interface for the O.S. to communicate with the hardware.  OS designers have a list of what operations they need certain classes of hardware to support, and the device manufacturers create the drivers that meet those specifications (and ideally create the hardware to operate with any default drivers so there will be at least some functionality, if minimal).

 

Now while I don't have any experience with this specific subject, I have worked with low level code before, so I can give you at least some idea of what happens.

 

1)  Yes, there will be assembly language involved.  Generally however, it's kept to as little as possible.  You'll write functions in assembly that you can then call from your C/C++. 

Some resources for that

Calling Conventions

x64 Software Conventions

 

These are usually simple modules, primarily to be building blocks for the code you'll write in C (and that is C, not C++). You'll likely have several functions that get you the status of the various hardware you're using, probably a function who's purpose is to take a pointer that holds the packet you want to send and sends it to the hardware, and another to read a packet from the nic.  While in theory you could write all the code you need in assembly, it would likely just create more problems that you'd solve.  Again, the goal is to make building blocks, to create functions that simply having to interact with the hardware.

 

From there, one function you would use those building blocks to make is the interrupt handler, so that everytime the nic informs the cpu it needs something dealt with, the O.S. can call that function to have it taken care of.

For some more info on interrupts you can start here

O.S. Basics

 

I know this is probably a lot more than you were thinking, but my main point is that while trying to solve one problem, you could open yourself up to a whole new load of issues.  And while in all honesty to a certain extent this stuff gets simpler, it' also gets very tedious, not to mention you find yourself having to work with hardware conventions designed decades ago and never properly updated.

 

Additionally, I think you're going about the wrong way of solving you're problem.  Correct me if I'm wrong, but it sounds like you're main concern is portability.  You don't want to have to use multiple libraries for different platforms, etc.  And while I do get that concern, I think you need to consider the ROI on the time spent working on a project like this.  Using an existing library you could write the code in likely a few days that works for 90% or more of the platforms you're application will be run on, vs spending months writing code that will run on 99.999% of platforms (and that's assuming it's possible in the first place).

 

And that's all ignoring what I consider the most important part: the experience.  As a wise man semi-stoned actor once said, "Just.  Do it."

While I am a big believer in people taking the time to plan out their program before they start it, but there's also a lot to be said for just going out and building a proof of concept.  I generally find people underestimate the value in just building something, even if it doesn't get put into production.

 

So I really what you need to ask yourself is what's the priority here?  Functionality, or education.  If it's education, then have fun, go balls to the wall.  I'd highly recommend you get a keep, used machine because you will be crashing it.

But if it's about getting something working, then start with what's already available.  As another one of my favorite quotes goes, "Premature optimization is the root of all evil", and while I have to stretch the definitions a bit, I believe that fits here.  Get a working version first, then decided what needs to be changed to suit all your needs.

 

 

 

 

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12349566
Share on other sites

Link to post
Share on other sites

20 minutes ago, wasab said:

Low level programming is hardcore(not in difficult but in being tedious) and assembly isn't fun. Always seek out libraries and avoid these stuffs if you can. Just my 2 cents. 

Low level programming is stupid easy presuming you have the programming manual and the system is using memory mapped I/O. You literally map symbols (pointers if you're doing C, labels if you're doing ASM) to the hardware addresses and use them like any other variable.

 

It's OSes that make things different depending on the level of control you want. If you want a high level of control, then it make things harder if the level of abstraction is high.

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12352239
Share on other sites

Link to post
Share on other sites

29 minutes ago, Mira Yurizaki said:

Low level programming is stupid easy presuming you have the programming manual and the system is using memory mapped I/O. You literally map symbols (pointers if you're doing C, labels if you're doing ASM) to the hardware addresses and use them like any other variable.

 

It's OSes that make things different depending on the level of control you want. If you want a high level of control, then it make things harder if the level of abstraction is high.

Still tedious. 10 lines of code in assembly  just to do what I can do with 2 lines in higher language. 

 

Less control but so much more productive. Many C++ programmer don't even bother doing hands on memory managing anymore. They had already ditch the raw printer with more modern smart pointers to help them avoid these stuffs. Only go low level IF you need to and there are very few rare cases when you do need to. 

 

Sudo make me a sandwich 

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12352308
Share on other sites

Link to post
Share on other sites

53 minutes ago, wasab said:

Still tedious. 10 lines of code in assembly  just to do what I can do with 2 lines in higher language. 

Depending on the type of operand that needs to be sent off, manipulating a GPIO can still be done in a single line of assembly. And even then depending on the ISA you could still do it in a single line of assembly regardless of the operand type.

Quote

Less control but so much more productive. Many C++ programmer don't even bother doing hands on memory managing anymore. They had already ditch the raw printer with more modern smart pointers to help them avoid these stuffs. Only go low level IF you need to and there are very few rare cases when you do need to.

I'm not saying that any of this is bad, but there are tradeoffs here. If you want more direct control and performance, abstractions are just going to get in the way of that. If you want to just get something done, then they're more helpful.

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12352412
Share on other sites

Link to post
Share on other sites

20 minutes ago, straight_stewie said:

Well that's a purely subjective statement.

I find assembly to be quite fun on at least two out of the three real world architectures that I have experience with.

To add, if you're at the assembly level, you're probably dealing with something simple enough anyway. At least to the point where you're not thinking about abstract concepts like a networking stack or whatever. You're down to the "what pin do I need to poke?" level

 

If you need a library, chances are it's because the thing is complicated.

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12352472
Share on other sites

Link to post
Share on other sites

15 hours ago, wasab said:

Many C++ programmer don't even bother doing hands on memory managing anymore. They had already ditch the raw printer with more modern smart pointers to help them avoid these stuffs.

Smart pointers remove the need to manually delete pointers, but you still need to understand the memory model to understand a lot of important things in C++. Copy constructors, move semantics, references etc. Other than the reference counting, smart pointers are still pointers (they are literally just a raw pointers wrapped with some reference shenanigans to deallocate that memory when the reference count hits 0, and also prevent copying in the case of unique_ptr)

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12353635
Share on other sites

Link to post
Share on other sites

On 2/28/2019 at 11:56 PM, fpo said:

TL;DR

Where’s a good resource in accessing hardware components with C or C++? 

 

Long

I was having trouble finding a nice standard library for network programming in C++. More or less, I’ve come to see nearly every compiler & OS has a different library assuming it even comes with one. 

I was hoping there’d be a method to access the network hardware directly & maybe just write the data to the components I want sent. 

It’d also be interesting to me if I could access other important pieces of hardware if I needed it. 

 

About why

I’ve been using & prototyping in C# however gritty graphics programming in C# is less convenient IMO. I’ve been considering switching to C++ for its neat features & vast native libraries. (Not many libraries in C++ are wrappers compared to C#)

I’m jealous of 8-bit guy & his ability to access everything he needs with Assembly. (Not that I’d like to do 15+ lines of code to just print something to the screen.)

When we're talking about PC, and not embedded systems such as small micro-controllers and such, accessing the hardware directly is only done when writing your own kernel or writing device drivers.

 

It's not simply a matter of direct hardware access being cumbersome,as already mentioned because the sheer number of different makes and models of devices out there, it's simply not allowed. User application software runs in security ring 3 on modern multitasking PC's, and in ring 3 you pretty much can't do anything. You cannot access memory that does not belong to your application. You can't access CPU  I/O ports. You're not allowed to raise bios interrupts to call bios routines, etc...

 

The reason should be obvious. You're sharing resources with all the other applications on the system. You can't just take control of the network hardware, there's other applications that want to do network stuff. Same goes for audio, video, etc. All such requests need to pass trough the OS, using the API's meant for the job, so the OS can act as referee.

 

It's also a matter of security. Imagine some application can simply take a look at the memory firefox is using at that moment in time while you're web-banking. It would be rather easy to steal sensitive information. Because an application cannot access memory that does not belong to the application such things are made impossible.

Link to comment
https://linustechtips.com/topic/1039334-accessing-hardware-cc/#findComment-12353741
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×