Skip to content

Instantly share code, notes, and snippets.

@amir-saniyan
Last active March 11, 2024 08:48
Show Gist options
  • Save amir-saniyan/854db35a789f07e61f48994b07d236df to your computer and use it in GitHub Desktop.
Save amir-saniyan/854db35a789f07e61f48994b07d236df to your computer and use it in GitHub Desktop.
Raspberry Pi Hardware ID

In the name of God

Raspberry Pi Hardware ID

The following C++ code, shows how to get Raspberry Pi hardware ID(s) in various ways. You can concatenate the strings and calculate it's hash to take Raspberry Pi Fingerprint:

rpid.cpp:

#include <cstdint>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <streambuf>
#include <sstream>
#include <string>

#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

// Header: /opt/vc/include/bcm_host.h
// Library: /opt/vc/lib/libbcm_host.so
#include <bcm_host.h>

// ----------------------------------------------------------------------------------------------------

std::string ReadCPUInfo()
{
    std::ifstream fileStream("/proc/cpuinfo");

    if(!fileStream)
    {
        throw std::runtime_error("Could not open: `/proc/cpuinfo`.");
    }

    std::string cpuinfo((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
                 
    fileStream.close();

    return cpuinfo;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadSysBoardModel()
{
    std::ifstream fileStream("/sys/firmware/devicetree/base/model");

    if(!fileStream)
    {
        throw std::runtime_error("Could not open: `/sys/firmware/devicetree/base/model`.");
    }

    std::string model((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
                 
    fileStream.close();

    return model;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadSysBoardSerial()
{
    std::ifstream fileStream("/sys/firmware/devicetree/base/serial-number");

    if(!fileStream)
    {
        throw std::runtime_error("Could not open: `/sys/firmware/devicetree/base/serial-number`.");
    }

    std::string serial((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
                 
    fileStream.close();

    return serial;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadSysMACAddress()
{
    std::ifstream fileStream("/sys/class/net/eth0/address");

    if(!fileStream)
    {
        throw std::runtime_error("Could not open: `/sys/class/net/eth0/address`.");
    }

    std::string address((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
                 
    fileStream.close();

    return address;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadMailboxBoardModel()
{
    int fd = open("/dev/vcio", 0);
    
    if (fd == -1)
    {
        throw std::runtime_error("Could not open: `/dev/vcio`.");
    }

    uint32_t property[32] =
    {
        0x0000001C, // Buffer size in bytes (including the header values, the end tag and padding): 7 * 4 = 28 = 0x1C.
        0x00000000, // Request code: 0x00000000 = process request.
        0x00010001, // Tag identifier: Get board model.
        0x00000004, // Value buffer size in bytes: 1 * 4 = 4 = 0x4.
        0x00000000, // Request code: b31 clear: request, b30-b0: reserved.
        0x00000000, // Value buffer.
        0x00000000  // End tag: 0x0
    };

    const unsigned long MAJOR_NUM = 100;
    if (ioctl(fd, _IOWR(MAJOR_NUM, 0, char*), property) < 0)
    {
        close(fd);
        throw std::runtime_error("`ioctl` failed.");
    }

    if (property[1] != 0x80000000)
    {
        close(fd);
        throw std::runtime_error("Request failed.");
    }

    close(fd);

    std::stringstream stream;
    stream << std::hex << property[5];
    std::string result = stream.str();
    
    return result;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadMailboxBoardRevision()
{
    int fd = open("/dev/vcio", 0);
    
    if (fd == -1)
    {
        throw std::runtime_error("Could not open: `/dev/vcio`.");
    }

    uint32_t property[32] =
    {
        0x0000001C, // Buffer size in bytes (including the header values, the end tag and padding): 7 * 4 = 28 = 0x1C.
        0x00000000, // Request code: 0x00000000 = process request.
        0x00010002, // Tag identifier: Get board revision.
        0x00000004, // Value buffer size in bytes: 1 * 4 = 4 = 0x4.
        0x00000000, // Request code: b31 clear: request, b30-b0: reserved.
        0x00000000, // Value buffer.
        0x00000000  // End tag: 0x0
    };

    const unsigned long MAJOR_NUM = 100;
    if (ioctl(fd, _IOWR(MAJOR_NUM, 0, char*), property) < 0)
    {
        close(fd);
        throw std::runtime_error("`ioctl` failed.");
    }

    if (property[1] != 0x80000000)
    {
        close(fd);
        throw std::runtime_error("Request failed.");
    }

    close(fd);

    std::stringstream stream;
    stream << std::hex << property[5];
    std::string result = stream.str();
    
    return result;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadMailboxBoardSerial()
{
    int fd = open("/dev/vcio", 0);
    
    if (fd == -1)
    {
        throw std::runtime_error("Could not open: `/dev/vcio`.");
    }

    uint32_t property[32] =
    {
        0x00000020, // Buffer size in bytes (including the header values, the end tag and padding): 8 * 4 = 32 = 0x20.
        0x00000000, // Request code: 0x00000000 = process request.
        0x00010004, // Tag identifier: Get board serial.
        0x00000008, // Value buffer size in bytes: 2 * 4 = 8 = 0x8.
        0x00000000, // Request code: b31 clear: request, b30-b0: reserved.
        0x00000000, // Value buffer.
        0x00000000, // Value buffer.
        0x00000000  // End tag: 0x0
    };

    const unsigned long MAJOR_NUM = 100;
    if (ioctl(fd, _IOWR(MAJOR_NUM, 0, char*), property) < 0)
    {
        close(fd);
        throw std::runtime_error("`ioctl` failed.");
    }

    if (property[1] != 0x80000000)
    {
        close(fd);
        throw std::runtime_error("Request failed.");
    }

    close(fd);

    std::stringstream stream;
    stream << std::hex << property[5]; // property[6] ignored.
    std::string result = stream.str();
    
    return result;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadMailboxMACAddress()
{
    int fd = open("/dev/vcio", 0);
    
    if (fd == -1)
    {
        throw std::runtime_error("Could not open: `/dev/vcio`.");
    }

    uint32_t property[32] =
    {
        0x00000020, // Buffer size in bytes (including the header values, the end tag and padding): 8 * 4 = 32 = 0x20.
        0x00000000, // Request code: 0x00000000 = process request.
        0x00010003, // Tag identifier: Get board MAC address.
        0x00000008, // Value buffer size in bytes: 2 * 4 = 8 = 0x8.
        0x00000000, // Request code: b31 clear: request, b30-b0: reserved.
        0x00000000, // Value buffer.
        0x00000000, // Value buffer.
        0x00000000  // End tag: 0x0
    };

    const unsigned long MAJOR_NUM = 100;
    if (ioctl(fd, _IOWR(MAJOR_NUM, 0, char*), property) < 0)
    {
        close(fd);
        throw std::runtime_error("`ioctl` failed.");
    }

    if (property[1] != 0x80000000)
    {
        close(fd);
        throw std::runtime_error("Request failed.");
    }

    close(fd);
    
    unsigned char* ptr = reinterpret_cast<unsigned char*>(&property[5]);

    std::stringstream stream;
    stream
        << std::hex
        << static_cast<int>(ptr[0]) << ":"
        << static_cast<int>(ptr[1]) << ":"
        << static_cast<int>(ptr[2]) << ":"
        << static_cast<int>(ptr[3]) << ":"
        << static_cast<int>(ptr[4]) << ":"
        << static_cast<int>(ptr[5]);
    std::string result = stream.str();
    
    return result;
}

// ----------------------------------------------------------------------------------------------------

std::string ReadOTPDump()
{
    bcm_host_init();
    
    char buffer[1024] = { 0 };

    if (vc_gencmd(buffer, sizeof(buffer), "otp_dump") != 0)
    {
        bcm_host_deinit();
        throw std::runtime_error("Could not execute `otp_dump` command.");
    }
    
    bcm_host_deinit();
    
    std::string otpDump = buffer;

    return otpDump;
}

// ----------------------------------------------------------------------------------------------------

int main()
{
    std::cout << "-------------------- CPU Info: $ cat /proc/cpuinfo --------------------" << std::endl;
    std::cout << ReadCPUInfo() << std::endl;
    
    std::cout << "-------------------- Board Model: $ cat /sys/firmware/devicetree/base/model --------------------" << std::endl;
    std::cout << ReadSysBoardModel() << std::endl;
    
    std::cout << "-------------------- Board Serial: $ cat /sys/firmware/devicetree/base/serial-number --------------------" << std::endl;
    std::cout << ReadSysBoardSerial() << std::endl;
    
    std::cout << "-------------------- MAC Address: $ cat /sys/class/net/eth0/address --------------------" << std::endl;
    std::cout << ReadSysMACAddress() << std::endl;
    
    std::cout << "-------------------- Board Model: $ /opt/vc/bin/vcmailbox 0x10001 0x4 0x0 0x0 --------------------" << std::endl;
    std::cout << ReadMailboxBoardModel() << std::endl;
    
    std::cout << "-------------------- Board Revision: $ /opt/vc/bin/vcmailbox 0x10002 0x4 0x0 0x0 --------------------" << std::endl;
    std::cout << ReadMailboxBoardRevision() << std::endl;
    
    std::cout << "-------------------- Board Serial: $ /opt/vc/bin/vcmailbox 0x10004 0x8 0x0 0x0 0x0 --------------------" << std::endl;
    std::cout << ReadMailboxBoardSerial() << std::endl;
    
    std::cout << "-------------------- MAC Address: $ /opt/vc/bin/vcmailbox 0x10003 0x8 0x0 0x0 0x0 --------------------" << std::endl;
    std::cout << ReadMailboxMACAddress() << std::endl;
        
    std::cout << "-------------------- OTP: vcgencmd otp_dump --------------------" << std::endl;
    std::cout << ReadOTPDump() << std::endl;

    return 0;
}

Build

To build the code, run the following command on Raspberry Pi terminal:

$ g++ \
    rpid.cpp \
    -I/opt/vc/include/ \
    -L/opt/vc/lib/ \
    -lbcm_host \
    -o rpid

$ ./rpid

Sample Output

The following text generated by rpid on my device:

-------------------- CPU Info: $ cat /proc/cpuinfo --------------------
processor	: 0
model name	: ARMv7 Processor rev 4 (v7l)
BogoMIPS	: 38.40
Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 1
model name	: ARMv7 Processor rev 4 (v7l)
BogoMIPS	: 38.40
Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 2
model name	: ARMv7 Processor rev 4 (v7l)
BogoMIPS	: 38.40
Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 3
model name	: ARMv7 Processor rev 4 (v7l)
BogoMIPS	: 38.40
Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

Hardware	: BCM2835
Revision	: a22082
Serial		: 00000000cae4d6b2
Model		: Raspberry Pi 3 Model B Rev 1.2

-------------------- Board Model: $ cat /sys/firmware/devicetree/base/model --------------------
Raspberry Pi 3 Model B Rev 1.2
-------------------- Board Serial: $ cat /sys/firmware/devicetree/base/serial-number --------------------
00000000cae4d6b2
-------------------- MAC Address: $ cat /sys/class/net/eth0/address --------------------
b8:27:eb:e4:d6:b2

-------------------- Board Model: $ /opt/vc/bin/vcmailbox 0x10001 0x4 0x0 0x0 --------------------
0
-------------------- Board Revision: $ /opt/vc/bin/vcmailbox 0x10002 0x4 0x0 0x0 --------------------
a22082
-------------------- Board Serial: $ /opt/vc/bin/vcmailbox 0x10004 0x8 0x0 0x0 0x0 --------------------
cae4d6b2
-------------------- MAC Address: $ /opt/vc/bin/vcmailbox 0x10003 0x8 0x0 0x0 0x0 --------------------
b8:27:eb:e4:d6:b2
-------------------- OTP: vcgencmd otp_dump --------------------
08:00000000
09:00000000
10:00000000
11:00000000
12:00000000
13:00000000
14:00000000
15:00000000
16:00280000
17:1020000a
18:1020000a
19:ffffffff
20:ffffffff
21:ffffffff
22:ffffffff
23:ffffffff
24:ffffffff
25:ffffffff
26:ffffffff
27:00002727
28:cae4d6b2
29:351b294d
30:00a22082
31:00000000
32:00000000
33:00000000
34:00000000
35:00000000
36:00000000
37:00000000
38:00000000
39:00000000
40:00000000
41:00000000
42:00000000
43:00000000
44:00000000
45:00000000
46:00000000
47:00000000
48:00000000
49:00000000
50:00000000
51:00000000
52:00000000
53:00000000
54:00000000
55:00000000
56:00000000
57:00000000
58:00000000
59:00000000
60:00000000
61:00000000
62:00000000
63:00000000
64:00000000
65:00000000
66:00000000

Bash

You can run the following command on terminal to extract Hardware ID:

$ cat /proc/cpuinfo
$ cat /sys/firmware/devicetree/base/model
$ cat /sys/firmware/devicetree/base/serial-number
$ cat /sys/class/net/eth0/address
$ /opt/vc/bin/vcmailbox 0x10001 0x4 0x0 0x0
$ /opt/vc/bin/vcmailbox 0x10002 0x4 0x0 0x0
$ /opt/vc/bin/vcmailbox 0x10004 0x8 0x0 0x0 0x0
$ /opt/vc/bin/vcmailbox 0x10003 0x8 0x0 0x0 0x0
$ vcgencmd otp_dump

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment