Circle - C++ bare metal environment for Raspberry Pi
Note
The latest information refers to the current development version on the develop branch.
License
Copyright © 2020-2021, Rene Stange

This documentation of Circle - C++ bare metal environment for Raspberry Pi is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Foreword
This documentation has been written to help Circle users to write great bare metal applications. If you want to help to improve this documentation, please give feedback in the Project issues or send a Pull request, if you have corrections or improvements.
Introduction
The Circle project provides a C++ bare metal environment for the Raspberry Pi single-board computers (SBC). This is a framework for developing applications, which run on the bare hardware, without using an operating system, which is somewhat equivalent to programming a very powerful micro-controller. Frequent areas of application for the bare metal system model are:
High-speed data acquisition (DAQ)
Retro computer emulation with accurate timing
Low latency, high performance audio processing
Characteristics of bare metal solutions can be:
Low interrupt latency
Full system control 1
Light-weighted software architecture 2
Direct hardware access 3
Quick system start (boot)
Can power off the system at any time 4
This documentation provides the necessary information for developing bare metal applications using Circle.
Footnotes
Getting started
To start using Circle, you need to download the project and a toolchain 1, configure Circle for your target platform, build the Circle libraries and your application 2, and install the built binary image (the kernel image) 3 on a SD card, along with a number of firmware files. In some cases an additional configuration file config.txt is needed on the SD card. The following notes require a x86_64 PC running Linux as development host. The file doc/windows-build.txt describes, how Windows can be used instead.
Download
The Circle project can be downloaded using Git as follows:
cd /path/to/your/projects
git clone https://github.com/rsta2/circle.git
The recommended toolchains for building Circle applications can be downloaded from here. Please note that there are different toolchains for 32-bit (AArch32, normally arm-none-eabi-) and for 64-bit (AArch64, normally aarch64-none-elf-) targets.
Configuration
Circle is configured using the file Config.mk in the project’s root directory. This file can be created using the configure
script, which provides these options:
-r <number>, --raspberrypi <number>
Raspberry Pi model number (1, 2, 3, 4, default: 1)
-p <string>, --prefix <string>
Prefix of the toolchain commands (default: arm-none-eabi-)
--multicore Allow multi-core applications
--realtime Enable real time mode to improve IRQ latency
--keymap <country> Set default USB keymap (DE, ES, FR, IT, UK, US)
--qemu Build for running under QEMU
-d <option>, --define <option>
Define additional system option
--c++17 Use C++17 standard for compiling (default C++14)
-f, --force Overwrite existing Config.mk file
-h, --help Show usage message
If you want to configure Circle for a Raspberry Pi 3 with the default toolchain prefix arm-none-eabi-
, with the toolchain path in the system PATH
variable, from Circle’s project root enter simply:
./configure -r 3
The file Config.mk can also be created by yourself. A typical 32-bit configuration looks like this:
PREFIX = /path/to/your/toolchain/bin/arm-none-eabi-
AARCH = 32
RASPPI = 3
This sets the path and name of your toolchain, and the architecture and model of your Raspberry Pi 4 computer.
Note
The configurable system options, described in the file include/circle/sysconfig.h, can be defined there or in the Config.mk file, like that:
DEFINE += -DOPTION_NAME
System options, which are enabled by default, can be disabled with:
DEFINE += -DNO_OPTION_NAME
A typical 64-bit configuration looks like that:
PREFIX64 = /path/to/your/toolchain/bin/aarch64-none-elf-
AARCH = 64
RASPPI = 3
64-bit operation is possible on the Raspberry Pi 3, 4 and Zero 2 only.
Building
After configuring Circle, go to the root directory of the Circle project and enter:
./makeall clean
./makeall
By default only the latest sample (with the highest number) is build. The ready build kernel image file should be in its subdirectory of sample/. If you want to build another sample after ./makeall
go to its subdirectory and do make
.
Installation
Copy the Raspberry Pi firmware (from boot/ subdirectory, do make
there to get them) files along with the kernel*.img (from sample/ subdirectory) to a SD card with FAT file system.
The config32.txt file, provided in the boot/ subdirectory, is needed to enable FIQ use in 32-bit mode on the Raspberry Pi 4 and has to be copied to the SD card in this case (rename it to config.txt). Furthermore the additional file armstub7-rpi4.bin is required on the SD card then. Please see boot/README for information on how to build this file.
The config64.txt file, provided in the boot/ directory, is needed to enable 64-bit mode and has to be copied to the SD card in this case (rename it to config.txt). FIQ support for 64-bit mode on the Raspberry Pi 4 requires an additional file armstub8-rpi4.bin on the SD card. Please see boot/README for information on how to build this file.
Put the SD card into your Raspberry Pi and power it on.
Footnotes
- 1
A toolchain in this context is cross compiler with additional tools and libraries, which runs on a specific platform and builds binaries for another (normally different) platform.
- 2
For a start this can be one of the provided sample programs.
- 3
Depending on the Raspberry Pi model and the target architecture (32- or 64-bit) a binary image has the filename kernel.img, kernel7.img, kernel7l.img, kernel8.img or kernel8-rpi4.img.
- 4
For the Raspberry Pi Zero and Zero W the target
RASPPI = 1
has to be configured. The Raspberry Pi Zero 2 W requires the targetRASPPI = 3
.
Hello world!
Now we want to start developing our first Circle program. It may look like this:
#include <circle/startup.h> // for EXIT_HALT
#include <circle/actled.h>
#include <circle/timer.h>
int main (void)
{
CActLED ActLED;
for (unsigned i = 1; i <= 10; i++)
{
ActLED.On ();
CTimer::SimpleMsDelay (200);
ActLED.Off ();
CTimer::SimpleMsDelay (500);
}
return EXIT_HALT;
}
The program should be self-explanatory. CTimer::SimpleMsDelay()
is a static delay function, which can be used, when there is no instance of the class CTimer
in the system.
For a first test create a subdirectory in the app/ directory and save this program as main.cpp there. Furthermore you need the following Makefile in the same directory:
CIRCLEHOME = ../..
OBJS = main.o
LIBS = $(CIRCLEHOME)/lib/libcircle.a
include $(CIRCLEHOME)/Rules.mk
-include $(DEPS)
Now enter make
in this directory and copy the resulting kernel*.img file to the SD card. When you power on your Raspberry Pi, the green Activity LED should blink ten times. Then the system halts.
The CKernel class
Normally an application is not that simple and we should apply some structure to our program, which can be used for any Circle application. In C++ the means of abstraction is a class and we want to define our application’s main class now. In Circle it is usually called CKernel
. It is a good practice to separate class definitions from its implementation, so we define the class in the header file kernel.h:
#ifndef _kernel_h
#define _kernel_h
//#include <circle/memory.h>
#include <circle/actled.h>
#include <circle/types.h>
enum TShutdownMode
{
ShutdownNone,
ShutdownHalt,
ShutdownReboot
};
class CKernel
{
public:
CKernel (void);
~CKernel (void);
boolean Initialize (void);
TShutdownMode Run (void);
private:
//CMemorySystem m_Memory; // not needed any more
CActLED m_ActLED;
};
#endif
You should create a new subdirectory under app/ and save this file there. Beside the class constructor CKernel()
and destructor ~CKernel()
there are the methods Initialize()
and Run()
. This implements a three step initialization for the class members, which is common throughout Circle:
The constructor
CKernel()
does some basic initialization for the class member variables.The method
Initialize()
completes the initialization of the class members and returnsTRUE
, if the initialization was successful.The method
Run()
is entered to start the execution of the application. When it returns, the application halts or the system reboots, depending of the returned value of typeTShutdownMode
. Many applications never return fromRun()
.
Note
Circle uses the type boolean
with the possible values TRUE
and FALSE
for historical reasons. You can use bool
, true
and false
instead, which is equivalent.
Note
Earlier Circle versions required a member of the class CMemorySystem
in CKernel
, which initializes and manages the system memory. An instance of CMemorySystem
is created now, before the function main()
is called, so that there is no need to add it to CKernel
any more. For compatibility CMemorySystem
may still be instantiated in CKernel
, but this is deprecated.
A possible class implementation for CKernel
, with the same function as the “Hello world!” program before, looks as follows:
#include "kernel.h"
#include <circle/timer.h>
CKernel::CKernel (void)
{
}
CKernel::~CKernel (void)
{
}
boolean CKernel::Initialize (void)
{
return TRUE;
}
TShutdownMode CKernel::Run (void)
{
for (unsigned i = 1; i <= 10; i++)
{
m_ActLED.On ();
CTimer::SimpleMsDelay (200);
m_ActLED.Off ();
CTimer::SimpleMsDelay (500);
}
return ShutdownHalt;
}
The class constructor CKernel()
and destructor ~CKernel()
and the method Initialize()
are not really used here, but this will change in real applications. Please note, that the constructor of the member variable m_ActLED
is implicitly called in CKernel()
. This call is automatically generated by the compiler.
Now that we have defined and implemented the class CKernel
, we still have to provide a main()
function, which implements the three step procedure given above for our class. This can be done as follows:
#include "kernel.h"
#include <circle/startup.h>
int main (void)
{
CKernel Kernel;
if (!Kernel.Initialize ())
{
halt ();
return EXIT_HALT;
}
TShutdownMode ShutdownMode = Kernel.Run ();
switch (ShutdownMode)
{
case ShutdownReboot:
reboot ();
return EXIT_REBOOT;
case ShutdownHalt:
default:
halt ();
return EXIT_HALT;
}
}
This main.cpp file is part of most Circle programs without changes.
Note
Because some destructors used in CKernel
may not be implemented, main()
never really returns, but calls halt()
or reboot()
instead. Because we want to provide a common implementation of main.cpp here, we have to accept this little flaw here. In fact with the described CKernel
implementation, it would be possible to return from main()
, but this need not be the case in other Circle applications.
Finally we have to add kernel.o to the Makefile listed above:
CIRCLEHOME = ../..
OBJS = main.o kernel.o
LIBS = $(CIRCLEHOME)/lib/libcircle.a
include $(CIRCLEHOME)/Rules.mk
-include $(DEPS)
That’s all. Now we have the basic structure of a Circle application and you should be able to build it using make
.
A more complex program
Now that we know, how the basic structure of a Circle application looks like, we want to add some more often used classes and thus functionality. The following program is based on the sample/04-timer. You will need a HDMI display or a serial terminal, connected to your Raspberry Pi, to try it out.
First create a new subdirectory below app/ and copy the files main.cpp and Makefile from the previously discussed program. These files remain unchanged. Only our CKernel
class will be modified and extended. The class definition looks now as follows:
#ifndef _kernel_h
#define _kernel_h
#include <circle/actled.h>
#include <circle/koptions.h>
#include <circle/devicenameservice.h>
#include <circle/screen.h>
#include <circle/serial.h>
#include <circle/exceptionhandler.h>
#include <circle/interrupt.h>
#include <circle/timer.h>
#include <circle/logger.h>
#include <circle/types.h>
enum TShutdownMode
{
ShutdownNone,
ShutdownHalt,
ShutdownReboot
};
class CKernel
{
public:
CKernel (void);
~CKernel (void);
boolean Initialize (void);
TShutdownMode Run (void);
private:
static void TimerHandler (TKernelTimerHandle hTimer,
void *pParam, void *pContext);
private:
CActLED m_ActLED;
CKernelOptions m_Options;
CDeviceNameService m_DeviceNameService;
CScreenDevice m_Screen;
CSerialDevice m_Serial;
CExceptionHandler m_ExceptionHandler;
CInterruptSystem m_Interrupt;
CTimer m_Timer;
CLogger m_Logger;
};
#endif
We add the following classes as member objects to CKernel
:
Class |
Purpose |
---|---|
CKernelOptions |
Provides command line options from cmdline.txt |
CDeviceNameService |
Maps device names to a pointer to the device object |
CScreenDevice |
Access to the HDMI display (screen) |
CSerialDevice |
Access to the serial interface (UART) |
CExceptionHandler |
Reports system faults (abort exceptions) for debugging |
CInterruptSystem |
Interrupt (IRQ and FIQ) handling |
CTimer |
Provides several time services |
CLogger |
System logging facility |
Furthermore a private static TimerHandler()
callback function is added, which is used to show the function of kernel timers, implemented by the CTimer
class. The file kernel.cpp has been updated like this:
#include "kernel.h"
static const char FromKernel[] = "kernel";
CKernel::CKernel (void)
: m_Screen (m_Options.GetWidth (), m_Options.GetHeight ()),
m_Timer (&m_Interrupt),
m_Logger (m_Options.GetLogLevel (), &m_Timer)
{
m_ActLED.Blink (5);
}
CKernel::~CKernel (void)
{
}
In the constructor of CKernel
the CScreenDevice
member is explicitly initialized using the display width and height from the configuration file cmdline.txt on the SD card. The display resolution can be selected in the first line of this file for example like this: width=640 height=480
. The CTimer
member uses interrupts (IRQ) to implement a system tick of 100 Hz and hence gets a pointer to the CInterruptSystem
member object.
Note
All Circle options for cmdline.txt are listed in doc/cmdline.txt. All options must be specified in the first line, separated with a space.
The system logging facility CLogger
is initialized with the wanted logging level and a pointer to the timer, so that it can log the system time. The logging level can be set in cmdline.txt by adding loglevel=N
, where N is a number between 0 (panic) and 4 (debug, default). Only the log messages with a severity of smaller or equal then this value will be logged.
boolean CKernel::Initialize (void)
{
boolean bOK = TRUE;
if (bOK)
{
bOK = m_Screen.Initialize ();
}
if (bOK)
{
bOK = m_Serial.Initialize (115200);
}
if (bOK)
{
CDevice *pTarget = m_DeviceNameService.GetDevice (
m_Options.GetLogDevice (), FALSE);
if (pTarget == 0)
{
pTarget = &m_Screen;
}
bOK = m_Logger.Initialize (pTarget);
}
if (bOK)
{
bOK = m_Interrupt.Initialize ();
}
if (bOK)
{
bOK = m_Timer.Initialize ();
}
return bOK;
}
In the Initialize()
method the second step of the class member initialization is done. The call to m_Logger.Initialize()
gets a pointer to the logging device as a parameter, which is &m_Screen
by default. If you add logdev=ttyS1
to cmdline.txt you can read the messages on a connected serial terminal. The mapping from device name to device object pointer takes place in m_DeviceNameService.GetDevice()
, which returns 0, if the device name is not found.
Important
The order of initialization is important. The same applies to the constructor and the order of member objects in the class definition in kernel.h.
TShutdownMode CKernel::Run (void)
{
m_Logger.Write (FromKernel, LogNotice,
"An exception will occur after 15 seconds from now");
m_Timer.StartKernelTimer (15 * HZ, TimerHandler);
unsigned nTime = m_Timer.GetTime ();
while (1)
{
while (nTime == m_Timer.GetTime ())
{
// just wait a second
}
nTime = m_Timer.GetTime ();
m_Logger.Write (FromKernel, LogNotice, "Time is %u", nTime);
}
return ShutdownHalt;
}
m_Logger.Write()
writes a message of the given severity to the system log. FromKernel
names the source of the message (see definition above). m_Timer.StartKernelTimer()
triggers, that the TimerHandler()
gets called after 15 seconds. m_Timer.GetTime()
returns the current local system time in seconds since 1970-01-01 00:00:00. Because we do not use a real-time clock, the actual time is equal to the uptime of the system. The program generates a log message every second on the screen or serial terminal, if it is selected as logging device.
void CKernel::TimerHandler (TKernelTimerHandle hTimer,
void *pParam, void *pContext)
{
void (*pInvalid) (void) = (void (*) (void)) 0x500000;
(*pInvalid) ();
}
After 15 seconds the TimerHandler()
is called and generates a “Prefetch abort” exception by jumping to the address 0x500000, because the memory region at this address is marked as “not executable”.
The Appendix Analyzing exceptions explains using this program, how the information can be analyzed, which is displayed, when an abort exception occurs.
Basic system services
This section describes the basic system services, which are provided for applications by the Circle base library libcircle.a. Only those classes are discussed here, which are directly used by applications. All Circle classes are listed in doc/classes.txt.
The Circle project does not provide a single centralized C++ header file. Instead the header file(s), which must be included for a specific class, function or macro definition are specified in the related subsection.
System information
This section describes the classes CMachineInfo
and CKernelOptions
, which provide information about the Raspberry Pi model, on which the application is running, and the runtime options, which can be defined in the file cmdline.txt on the SD card.
CMachineInfo
Normally there is exactly one instance of the class CMachineInfo
in the system, which is created by the Circle system initialization code. If another instance is created, it acts as an alias for the first instance.
#include <circle/machineinfo.h>
-
class CMachineInfo
-
static CMachineInfo *CMachineInfo::Get(void)
Returns a pointer to the first instance of
CMachineInfo
.
Model information
-
TMachineModel CMachineInfo::GetMachineModel(void) const
Returns the Raspberry Pi model, the application is running on. Possible values are:
MachineModelA
MachineModelBRelease1MB256
MachineModelBRelease2MB256
MachineModelBRelease2MB512
MachineModelAPlus
MachineModelBPlus
MachineModelZero
MachineModelZeroW
MachineModelZero2W
MachineModel2B
MachineModel3B
MachineModel3APlus
MachineModel3BPlus
MachineModelCM
MachineModelCM3
MachineModelCM3Plus
MachineModel4B
MachineModel400
MachineModelCM4
MachineModelUnknown
-
const char *CMachineInfo::GetMachineName(void) const
Returns the name of the Raspberry Pi model, the application is running on.
-
unsigned CMachineInfo::GetModelMajor(void) const
Returns the major version (1-4) of the Raspberry Pi model, the application is running on, or zero if it is unknown.
-
unsigned CMachineInfo::GetModelRevision(void) const
Returns the revision number (1-) of the Raspberry Pi model, the application is running on, or zero if it is unknown.
-
TSoCType CMachineInfo::GetSoCType(void) const
Returns the type of the SoC (System on a Chip), the application is running on. Possible values are:
SoCTypeBCM2835
SoCTypeBCM2836
SoCTypeBCM2837
SoCTypeBCM2711
SoCTypeUnknown
-
unsigned CMachineInfo::GetRAMSize(void) const
Returns the size of the SDRAM in MBytes of the Raspberry Pi model, the application is running on, or zero if it is unknown.
-
const char *CMachineInfo::GetSoCName(void) const
Returns the name of the SoC (System on a Chip), the application is running on.
-
u32 CMachineInfo::GetRevisionRaw(void) const
Returns the raw revision code of the Raspberry Pi model, the application is running on.
Clocks and peripherals
-
unsigned CMachineInfo::GetActLEDInfo(void) const
Returns the information, about how the green Activity LED is connected to the system. The result has to be masked with
ACTLED_PIN_MASK
to extract the GPIO pin number. If the result masked withACTLED_ACTIVE_LOW
is not zero, the LED is on, when the value 0 is written to the GPIO pin. If the result masked withACTLED_VIRTUAL_PIN
is not zero, the LED is connected to a GPIO expander, which is controlled by the firmware.
-
unsigned CMachineInfo::GetClockRate(u32 nClockId) const
Returns the current frequency in Hz of the system clock, selected by
nClockId
, which can have the following values:
CLOCK_ID_CORE
CLOCK_ID_ARM
CLOCK_ID_UART
CLOCK_ID_EMMC
CLOCK_ID_EMMC2
-
unsigned CMachineInfo::GetGPIOPin(TGPIOVirtualPin Pin) const
Returns the physical GPIO pin number of the PWM audio pins.
Pin
can have the valuesGPIOPinAudioLeft
orGPIOPinAudioRight
.
-
unsigned CMachineInfo::GetGPIOClockSourceRate(unsigned nSourceId)
This method allows to enumerate the different clock sources for GPIO clocks. It returns the frequency in Hz of the GPIO clock source with the ID
nSourceId
, which can be zero toGPIO_CLOCK_SOURCE_ID_MAX
. The returned value isGPIO_CLOCK_SOURCE_UNUSED
, if the clock source is unused.
-
unsigned CMachineInfo::GetDevice(TDeviceId DeviceId) const
Returns the device number of the default I2C master in the system.
DeviceId
has to be set toDeviceI2CMaster
.
-
boolean CMachineInfo::ArePWMChannelsSwapped(void) const
Returns
TRUE
, if the left PWM audio channel is PWM1 (not PWM0).
DMA channels
-
unsigned CMachineInfo::AllocateDMAChannel(unsigned nChannel)
Allocates an available DMA channel from the platform DMA controller.
nChannel
can beDMA_CHANNEL_NORMAL
(normal DMA engine requested),DMA_CHANNEL_LITE
(lite (or normal) DMA engine requested),DMA_CHANNEL_EXTENDED
(“large address” DMA4 engine requested, on Raspberry Pi 4 only) or an explicit channel number (0-15). Returns the allocated channel number orDMA_CHANNEL_NONE
on failure.
-
void CMachineInfo::FreeDMAChannel(unsigned nChannel)
Release an allocated DMA channel.
nChannel
is the channel number (0-15).
CKernelOptions
The class CKernelOptions
provides the values of runtime options, which can be defined in the file cmdline.txt on the SD card. The supported options are listed in doc/cmdline.txt. There is exactly one or no instance of this class in the system. Only relatively simple programs can work without an instance of CKernelOptions
.
#include <circle/koptions.h>
-
class CKernelOptions
-
static CKernelOptions *CKernelOptions::Get(void)
Returns a pointer to the only instance of
CKernelOptions
.
-
unsigned CKernelOptions::GetWidth(void) const
-
unsigned CKernelOptions::GetHeight(void) const
Return the requested width and height of the screen, or zero if not specified. These values will normally handed over to the constructor for the class
CScreenDevice
.
-
const char *CKernelOptions::GetLogDevice(void) const
-
unsigned CKernelOptions::GetLogLevel(void) const
Return the name of the target device for the system log (default
tty1
) and the log level (defaultLogDebug
), to be handed over to the constructor of the classCLogger
.
-
const char *CKernelOptions::GetKeyMap(void) const
Returns the country code of the requested keyboard map (option
keymap=
). The default can be set with the system optionDEFAULT_KEYMAP
.
-
unsigned CKernelOptions::GetUSBPowerDelay(void) const
Returns the requested USB power-on delay in milliseconds, or zero to use the default value.
-
boolean CKernelOptions::GetUSBFullSpeed(void) const
Returns
TRUE
, if the optionusbspeed=full
is given in cmdline.txt.
-
const char *CKernelOptions::GetSoundDevice(void) const
Returns the configured sound device (option
sounddev=
). Defaults to an empty string.
-
unsigned CKernelOptions::GetSoundOption(void) const
Returns the value configured with the option
soundopt=
in cmdline.txt (0-2, default 0).
-
TCPUSpeed CKernelOptions::GetCPUSpeed(void) const
Returns
CPUSpeedMaximum
, if the optionfast=true
is given in cmdline.txt, orCPUSpeedLow
otherwise.
-
unsigned CKernelOptions::GetSoCMaxTemp(void) const
Returns the enforced maximal temperature of the SoC (option
socmaxtemp=
) in degrees Celsius (default 60).
-
const unsigned *CKernelOptions::GetTouchScreen(void) const
Returns the calibration parameters for the touchscreen. The returned pointer refers to an array with four elements (min-x, max-x, min-y, max-y). It is
nullptr
, if the optiontouchscreen=
is not set.
Memory
Circle enables the Memory Management Unit (MMU) to be able to use the data cache of the CPU to speed up operation, but it does not make use of virtual memory to implement specific system features. The physical-to-virtual address mapping is one-to-one over the whole used memory space. 1 The memory layout for the different system configurations can be found in doc/memorymap.txt.
new and delete
Circle supports system heap memory. Memory can be allocated with the normal C++ new
operator and freed with the delete
operator. Allocating and freeing memory blocks is supported from TASK_LEVEL
and IRQ_LEVEL
, but not from FIQ_LEVEL
. 2 Allocated memory blocks are always aligned to the maximum size of a cache-line in the system. 3
Note
Circle keeps a number of linked lists to manage memory blocks of different sizes. The supported block sizes are defined by the system option HEAP_BLOCK_BUCKET_SIZES
. By default the maximum manageable block size is 512 KByte. Larger memory blocks can be allocated, but not re-used after delete
.
The new
operator can have a parameter, which specifies the type of memory to be allocated:
Parameter |
Description |
---|---|
HEAP_LOW |
memory below 1 GByte |
HEAP_HIGH |
memory above 1 GByte (on Raspberry Pi 4 only) |
HEAP_ANY |
memory above 1 GB (if available) or memory below 1 GB (otherwise) |
HEAP_DMA30 |
30-bit DMA-able memory (alias for HEAP_LOW) |
This is especially important on the Raspberry Pi 4, which supports different SDRAM memory regions. For instance one can specify to allocate a 256 byte memory block above 1 GByte:
#include <circle/new.h>
unsigned char *p = new (HEAP_HIGH) unsigned char[256];
Further information on using memory type parameters is available in doc/new-operator.txt.
CMemorySystem
#include <circle/memory.h>
-
class CMemorySystem
The class CMemorySystem
implements most of the memory management function inside Circle. There is normally exactly one instance of this class in each Circle application, which is created by the Circle system initialization code. Earlier versions of Circle required to explicitly create this instance in CKernel
. This is deprecated now, but does not disturb either. If another instance of CMemorySystem
is created, it is an alias for the first created instance.
Methods callable from applications are:
-
size_t CMemorySystem::GetMemSize(void) const
Returns the total memory size available to the application, as reported by the firmware.
-
size_t CMemorySystem::GetHeapFreeSpace(int nType) const
Returns the free space on the heap of the given type, according to the memory type
HEAP_LOW
,HEAP_HIGH
orHEAP_ANY
. Does not cover memory blocks, which have been freed.
-
static CMemorySystem *CMemorySystem::Get(void)
Returns a pointer to the instance of
CMemorySystem
.
-
static void CMemorySystem::DumpStatus(void)
Dumps some memory allocation status information. Requires
HEAP_DEBUG
to be defined.
CClassAllocator
The class CClassAllocator
allows to define a class-specific allocator for a class, using a pre-allocated store of memory blocks. This can speed up memory allocation, if the maximum number of instances of the class is known and a class instance does not occupy too much memory space. If you want to use this technique for your own class, the class definition has to look like this:
#include <circle/classallocator.h>
class CMyClass
{
...
DECLARE_CLASS_ALLOCATOR
};
You have to add the following to the end of the class implementation file:
#include "myclass.h"
...
IMPLEMENT_CLASS_ALLOCATOR (CMyClass)
Before an instance of your class can be created, one of these (macro-) functions have to be executed:
#include "myclass.h"
INIT_CLASS_ALLOCATOR (CMyClass, Number); // or:
INIT_PROTECTED_CLASS_ALLOCATOR (CMyClass, Number, Level);
The second variant initializes a class-specific allocator, which is protected with a spin-lock for concurrent use. Number is the number of pre-allocated memory blocks and Level the maximum execution level, from which new
or delete
for this class will be called. 2
C functions
Circle provides the following C standard library functions for memory allocation:
#include <circle/alloc.h>
void *malloc (size_t nSize);
void *calloc (size_t nBlocks, size_t nSize);
void *realloc (void *pBlock, size_t nSize);
void free (void *pBlock);
Footnotes
- 1
There is one exception from this rule. On the Raspberry Pi 4 the memory mapped I/O register space of the xHCI USB controller, which is connected using a PCIe interface, is re-mapped into the 4 GByte 32-bit address space, because it is physically located above the 4 GByte boundary, and would not be accessible in 32-bit mode otherwise.
- 2(1,2)
System execution levels (e.g.
TASK_LEVEL
) are described in the section Synchronization.- 3
32 bytes on the Raspberry Pi 1 and Zero, 64 bytes otherwise
Synchronization
This section discusses the different system execution levels of code inside a Circle application and how they can be synchronized. Furthermore the class CSpinLock
will be introduced, which is the main synchronization object in multi-core environments, but also in single-core environments, because all Circle code should be prepared to run on multiple cores, at least where it is possible.
Execution levels
#include <circle/synchronize.h>
The current execution level is determined by the type of interrupt requests, which are enabled (i.e. allowed to occur) or active (i.e. currently handled) at a given time. Circle defines the following execution levels:
Level 1 |
Currently running |
Enabled interrupts |
---|---|---|
TASK_LEVEL |
normal application code or task 2 |
IRQ, FIQ |
IRQ_LEVEL |
IRQ handler or callback 3 |
FIQ |
FIQ_LEVEL |
FIQ handler |
Interrupt requests of the same type (i.e. IRQ or FIQ) cannot be nested. That means, when for example an IRQ handler is running for one device, a triggered IRQ of another device has to wait for the execution of its IRQ handler, until the previous IRQ handler has been completed.
The execution level (e.g. TASK_LEVEL
) of the currently running code is returned by the following function:
-
unsigned CurrentExecutionLevel(void)
The current execution level can be explicitly raised with this function:
-
void EnterCritical(unsigned nTargetLevel = IRQ_LEVEL)
EnterCritical()
can be called with the same as the current execution level or with a higher level, but not with a lower one. Reducing the current execution level is possible with this function:
-
void LeaveCritical(void)
In summary EnterCritical()
is called to enter a critical code region, which must not be interrupted by an IRQ, or by both IRQ and FIQ, depending on the target level. This critical region will be left with LeaveCritical()
. Calls to EnterCritical()
can be nested with the same or increasing target level. Every EnterCritical()
has its corresponding LeaveCritical()
.
Important
In a multi-core environment using EnterCritical()
for synchronization (e.g. protecting data structures in a critical region) is not recommended or does not work at all. You should use spin locks (see below) instead. Furthermore, because Circle source code should be able to run in any environment, where possible, it is good practice to use spin locks also for code, which is developed for a single-core environment. If the system option ARM_ALLOW_MULTI_CORE
is disabled, all spin lock operations mutate to calls of EnterCritical()
and LeaveCritical()
automatically.
Footnotes
- 1
These symbols are defined as C macros.
- 2
Tasks are discussed in the section Multitasking.
- 3
A number of callback functions in an Circle application (e.g. kernel timer handler) will be called directly from an IRQ handler.
CSpinLock
The class CSpinLock
implements a spin lock, which is a synchronization object in a multi-core environment. It can be used to protect a data structure, which is shared between multiple cores, from destruction, when multiple cores are trying to access this data structure at the same time. The spin lock serializes the access, so that only one core can write or read the data at a time.
#include <circle/spinlock.h>
-
class CSpinLock
In Circle a spin lock is initialized with this constructor:
-
CSpinLock::CSpinLock(unsigned nTargetLevel = IRQ_LEVEL)
nTargetLevel is the maximum execution level from which the spin lock is acquired and released.
-
void CSpinLock::Acquire(void)
This method tries to acquire the spin lock. It also raises the execution level to the level given to the constructor. If the spin lock is currently acquired by another core, the execution will be stalled, until the spin lock is released by the other core.
Important
Calls to Acquire()
cannot be nested for the same spin lock. If doing so, the execution will freeze. Multiple spin locks can be acquired in a row, but must be released in the opposite order. Otherwise a system deadlock may occur randomly.
CGenericLock
This class is used for mutual exclusion (critical sections) from TASK_LEVEL
, at places where it is not clear, if the scheduler (see Multitasking) is in the system and mutual exclusion must work between tasks or between multiple CPU cores otherwise. If the scheduler is available and the system option NO_BUSY_WAIT
is defined, this lock is implemented by the class CMutex
, otherwise by the class CSpinLock
.
#include <circle/genericlock.h>
-
class CGenericLock
-
void CGenericLock::Acquire(void)
Acquires the lock. Execution blocks, if another task or CPU core has already acquired the lock.
-
void CGenericLock::Release(void)
Releases the lock. Execution of another task or CPU core, which is waiting for the lock, continues.
Memory barriers
Memory barriers are system control CPU instructions, which influence the access to the main memory. They can be important especially in multi-core applications to ensure, that data has been written to or read from memory at a given place in the code.
When a variable is written by one CPU core in a multi-core environment, this is normally recognized by the other CPU cores, but for synchronization purposes barriers may be required, if a write or read operation must be completed at a specific place in code.
#include <circle/synchronization.h>
Circle defines the following memory barriers:
-
DataSyncBarrier()
This barrier (also known as DSB) ensures, that all memory read and write operations have been completed, at the place where it is inserted in the code. It may be required to insert this barrier, after an application has written data from one CPU core, which will be read from an other CPU core afterwards.
-
DataMemBarrier()
This barrier (also known as DMB) ensures, that all memory read operations have been completed, at the place where it is inserted in the code. It may be required to insert this barrier, before an application will read data, which has been written by an other CPU core before.
System log
Circle uses a system log facility throughout the system to report status information from other system facilities or devices to the user. It is recommended to use this log facility from application code too and this is implemented in all Circle sample programs. While an application may write information messages directly to a device, the log facility provides additional services and is a standard tool for collecting status information in Circle. The system log is implemented by the class CLogger
.
CLogger
#include <circle/logger.h>
-
class CLogger
There is exactly one or no instance of CLogger
in the system. Only relatively simple programs can work without an instance of CLogger
.
Initialization
-
CLogger::CLogger(unsigned nLogLevel, CTimer *pTimer = 0, boolean bOverwriteOldest = TRUE)
Creates the instance of
CLogger
.nLogLevel
(0-4) determines, which log messages are included in the system log. Only messages with a log level smaller or equal tonLogLevel
are considered.pTimer
is a pointer to the system timer object. The time is not logged, ifpTimer
is zero. The following log levels are defined:
Level |
Severity |
Description |
---|---|---|
0 |
LogPanic |
Halt the system after processing this message |
1 |
LogError |
Severe error in this component, system may continue to work |
2 |
LogWarning |
Non-severe problem, component continues to work |
3 |
LogNotice |
Informative message, which is interesting for the system user |
4 |
LogDebug |
Message, which is only interesting for debugging this component |
Set
bOverwriteOldest
toFALSE
, if you want to keep old log messages forRead()
, even when the text ring buffer is full (see Read the log).
Write the log
Read the log
CLogger
has a 16K (LOGGER_BUFSIZE
) sized text ring buffer, which saves the written log messages. If this buffer is full, old messages will be overwritten by default. This behavior can be changed with the parameter bOverwriteOldest
of the constructor.
-
int CLogger::Read(void *pBuffer, unsigned nCount, boolean bClear = TRUE)
Reads and deletes maximal
nCount
characters from the log buffer. The read characters will be returned inpBuffer
. SetbClear
toTRUE
to remove the returned bytes from the buffer or toFALSE
to keep them. Returns the number of characters actually read.
-
boolean CLogger::ReadEvent(TLogSeverity *pSeverity, char *pSource, char *pMessage, time_t *pTime, unsigned *pHundredthTime, int *pTimeZone)
Returns the next log event (message) from a log event queue with maximal 50 entries or
FALSE
, if the queue is empty. The buffers atpSource
andpMessage
must have the sizesLOG_MAX_SOURCE
andLOG_MAX_MESSAGE
. This queue is normally used by the class CSysLogDaemon, which sends log messages to a syslog server.
Log event notification
-
void CLogger::RegisterEventNotificationHandler(TLogEventNotificationHandler *pHandler)
Registers a callback function, which is executed, when a log event (message) arrives. This is normally used by the class CSysLogDaemon, which sends log messages to a syslog server.
TLogEventNotificationHandler
has the following prototype:
void TLogEventNotificationHandler (void);
-
void CLogger::RegisterPanicHandler(TLogPanicHandler *pHandler)
Registers a callback function, which is executed, before a system halt, which is triggered by a log message with severity
LogPanic
. This is normally used by the class CSysLogDaemon, which sends log messages to a syslog server. IfCSysLogDaemon
is not in the system,RegisterPanicHandler()
can be used for other application purposes.TLogPanicHandler
has to following prototype:
void TLogPanicHandler (void);
Quick access
The following macros allow a quick access to the system log.
-
LOGMODULE(name)
Defines the C-string
name
as a name for this source module for generating log messages with the macros below.
-
LOGPANIC(format, ...)
-
LOGERR(format, ...)
-
LOGWARN(format, ...)
-
LOGNOTE(format, ...)
-
LOGDBG(format, ...)
Writes a message with the given severity,
format
and optional parameters to the system log using the module name defined withLOGMODULE()
.
Interrupts
This section describes the low-level hardware-interrupt support in Circle. This should be only of interest, if one wants to develop its own device driver or driver-like functions.
In the ARM architecture there are two types of interrupt request, IRQ and FIQ. The IRQ is the basic interrupt request type, can have multiple active sources on all Raspberry Pi models and is used to control most interrupt-driven devices. The FIQ (Fast Interrupt Request) is used for low-latency interrupts and can have only one active interrupt source at a time on the Raspberry Pi 1-3 and Zero. The Raspberry Pi 4 has an new interrupt controller (GIC-400) and may theoretically support multiple simultaneous FIQ sources, but for a homogeneous solution this currently not supported in Circle. Therefore there are normally multiple active interrupt sources in a system, which use the IRQ, but only up to one, which uses the FIQ.
CInterruptSystem
The class CInterruptSystem
is the provider of hardware-interrupt support in Circle. Hardware-interrupt support is not mandatory in an application, but if it is used, there is exactly one instance of this class in the system.
#include <circle/interrupt.h>
-
class CInterruptSystem
-
boolean CInterruptSystem::Initialize(void)
Initializes the interrupt system. Returns
TRUE
on success.
Note
There is a two step initialization required for the interrupt system. Step one is done in the constructor of CInterruptSystem
, step two in Initialize()
.
-
void CInterruptSystem::ConnectIRQ(unsigned nIRQ, TIRQHandler *pHandler, void *pParam)
Connects an interrupt handler to an IRQ source (vector). The known interrupt sources are defined in
<circle/bcm2835int.h>
for the Raspberry Pi 1-3 and Zero and in<circle/bcm2711int.h>
for the Raspberry Pi 4. An IRQ handler has the following prototype:
void IRQHandler (void *pParam);
pParam
can be any user parameter and gets the value specified in the call to ConnectIRQ()
for this IRQ source.
-
void CInterruptSystem::DisconnectIRQ(unsigned nIRQ)
Disconnects the interrupt handler from the given IRQ source.
-
void CInterruptSystem::ConnectFIQ(unsigned nFIQ, TFIQHandler *pHandler, void *pParam)
Connects an interrupt handler to a FIQ source. Only one active FIQ source is allowed at a time. An FIQ handler has the same prototype as an IRQ handler (see above).
-
void CInterruptSystem::DisconnectFIQ(void)
Disconnects the interrupt handler of the active FIQ source.
-
static CInterruptSystem *CInterruptSystem::Get(void)
Returns a pointer to the only instance of
CInterruptSystem
.
Important
If one or more IRQ handlers in a system make use of floating point registers, the system option SAVE_VFP_REGS_ON_IRQ
has to be enabled. The same applies accordingly to SAVE_VFP_REGS_ON_FIQ
for FIQ handlers.
Time
This section describes the services, which are provided by Circle regarding time. This concerns:
The current non-consecutive system time (local and UTC) in seconds since 1970-01-01 00:00:00
The timezone, expressed in minutes +/- from UTC
The current consecutive system up-time in seconds
A coarse grained, consecutive system tick counter in 1/100 seconds
A fine grained, consecutive system tick counter in microseconds
A possibly greater number of kernel timers, which elapse after a given number of coarse system ticks, resulting in a callback function to be executed
Up to four periodic timer handlers, called 100 times per second
Delaying program execution for a number of milli-, micro- or nanoseconds
One fine grained periodic user timer, executing a callback function in an interval down to microseconds
Converting time values (seconds since 1970-01-01 00:00:00) into time components (i.e. year, month, day, hour, minute, seconds) or reversed or into a string representation
These services are implemented in the classes CTimer
, CUserTimer
and CTime
.
Note
“Consecutive” in this context means, that the time does never “jump”. For example the current local system time may be updated, while the system is running, from an external time source (e.g. NTP server). This may cause a step back or forward in time. Consecutive time sources ensure, that this does not happen, which is important, e.g. when a program waits for an amount of time to pass, by calculating the difference between the current time and a start time.
CTimer
This class is the main provider of time services in Circle.
#include <circle/timer.h>
-
class CTimer
There is exactly one or no instance of this class in the system. Only relatively simple programs can work without an instance of CTimer
. The only static timer functions, which can be called before this instance of CTimer
is created and initialized, are:
-
static unsigned CTimer::GetClockTicks(void)
Returns the current value of the fine grained, consecutive system tick counter in microseconds. It does not necessarily start at zero and may overrun after a while. It continues to count from zero then.
-
CLOCKHZ
Frequency of the fine grained, consecutive system tick counter (1000000).
-
static void CTimer::SimpleusDelay(unsigned nMicroSeconds)
Delay the program execution by the given amount of time.
Initialization
-
CTimer::CTimer(CInterruptSystem *pInterruptSystem)
Creates the instance of
CTimer
.
-
boolean CTimer::Initialize(void)
Initializes and activates the system timer services. Returns
TRUE
on success.
Note
CTimer::Initialize()
may generate log messages. Therefore it requires an initialized instance of the class CLogger
in the system.
CTimer::Initialize()
determines the CPU speed by calibrating a delay loop by default. This can be suppressed with the system option NO_CALIBRATE_DELAY
(e.g. to reduce boot time).
Local time and UTC
-
int CTimer::GetTimeZone(void) const
Sets or returns the current timezone in minutes difference to UTC.
-
boolean CTimer::SetTime(unsigned nTime, boolean bLocal = TRUE)
Sets the current system time in seconds since 1970-01-01 00:00:00. The time is given according to the timezone by default or in UTC, if the parameter
bLocal
is FALSE. ReturnsTRUE
, if the time is valid.
-
boolean CTimer::GetLocalTime(unsigned *pSeconds, unsigned *pMicroSeconds)
Returns the current local system time in seconds since 1970-01-01 00:00:00. The third variant always returns
TRUE
.
-
boolean CTimer::GetUniversalTime(unsigned *pSeconds, unsigned *pMicroSeconds)
Returns the current universal system time (UTC) in seconds since 1970-01-01 00:00:00. This value may be invalid, if the time was not set and the timezone difference is greater than zero. The third variant returns
FALSE
in this case.
Coarse system tick and up-time
-
unsigned CTimer::GetTicks(void) const
Returns the current value of the coarse grained, consecutive system tick counter in 1/100 seconds units.
Note
CTimer::GetTicks()
reads the ticks variable only and returns quickly. CTimer::GetClockTicks()
reads a hardware register (on Raspberry Pi 1 and Zero) or has to do some calculations (in 64-bit mode). Therefore calling CTimer::GetTicks()
does normally cost less CPU cycles. You should use CTimer::GetTicks()
, if its precision is sufficient for your purpose, or CTimer::GetClockTicks()
otherwise.
-
HZ
Frequency of the coarse grained, consecutive system tick counter (100).
Kernel timers
-
TKernelTimerHandle CTimer::StartKernelTimer(unsigned nDelay, TKernelTimerHandler *pHandler, void *pParam = 0, void *pContext = 0)
Start a kernel timer, which elapses after
nDelay
coarse system ticks (100 Hz). CallpHandler
on elapse with the given values ofpParam
andpContext
. Returns a handle to the started timer.TKernelTimerHandler
has the following prototype:
void TKernelTimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext);
-
MSEC2HZ(msecs)
A macro, which converts milliseconds into coarse system ticks.
Periodic timers
-
void CTimer::RegisterPeriodicHandler(TPeriodicTimerHandler *pHandler)
Register a periodic timer handler, which is called
HZ
times (100) per second. Up to four handlers are allowed.TPeriodicTimerHandler
has the following prototype:
void TPeriodicTimerHandler (void);
Update time handler
-
void CTimer::RegisterUpdateTimeHandler(TUpdateTimeHandler *pHandler)
Register a handler, which is called when
SetTime()
is invoked. This allows the application to apply additional checks, before the new time is set.
-
typedef boolean TUpdateTimeHandler(unsigned nNewTime, unsigned nOldTime)
The handler gets the
nNewTime
to be set and the currentnOldTime
in seconds since 1970-01-01 00:00:00 UTC, and returnsTRUE
, if the new time can be set orFALSE
, if the time is invalid. The call toSetTime()
is ignored then.
Delay
-
void CTimer::nsDelay(unsigned nNanoSeconds)
Delay the program execution by the given amount of time. These functions should be used, when an instance of
CTimer
is available in the system (i.e. instead ofSimpleMsDelay()
andSimpleusDelay()
).
Note
The actual delay may deviate from the requested value to some degree, but is never smaller than requested.
CUserTimer
This class implements a fine grained, user programmable interrupt timer. It uses the system timer 1 hardware, which must not be used for other purposes in the application then.
#include <circle/usertimer.h>
-
class CUserTimer
-
CUserTimer::CUserTimer(CInterruptSystem *pInterruptSystem, TUserTimerHandler *pHandler, void *pParam = 0, boolean bUseFIQ = FALSE)
Creates an instance of
CUserTimer
. Only one is allowed.pHandler
is a pointer to the callback function, which is executed, when the user timer elapses. By default the IRQ is used to trigger the interrupt.bUseFIQ
has to be set toTRUE
to use the FIQ instead (e.g. for high frequencies).TUserTimerHandler
has this prototype:
void TUserTimerHandler (CUserTimer *pUserTimer, void *pParam);
-
boolean CUserTimer::Initialize(void)
Initializes the user timer. Returns
TRUE
on success. Automatically starts the user timer with a delay of 1 hour.
-
void CUserTimer::Stop(void)
Stops the user timer. It has to be re-initialized to be used again.
-
void CUserTimer::Start(unsigned nDelayMicros)
(Re-)starts the user timer to elapse after the given number of microseconds (> 1). This method must be called from the user timer handler to a set new delay. It can be called on a running user timer to update the delay.
-
USER_CLOCKHZ
Frequency of the user timer (1000000).
CTime
This class converts the time into different representations.
#include <circle/time.h>
-
type time_t
Time representation (normally) in seconds since 1970-01-01 00:00:00.
-
class CTime
-
CTime::CTime(const CTime &rSource)
Creates an instance of
CTime
from a differentCTime
object (copy constructor).
-
boolean CTime::SetTime(unsigned nHours, unsigned nMinutes, unsigned nSeconds)
Sets the time from its components hours (0-23), minutes (0-59) and seconds (0-59). Returns
TRUE
if the time is valid.
-
boolean CTime::SetDate(unsigned nMonthDay, unsigned nMonth, unsigned nYear)
Sets the date from its components month-day (1-31), month (1-12) and year (1970-). Returns
TRUE
if the date is valid.
Direct Memory Access (DMA)
Circle supports Direct Memory Access (DMA) using the platform DMA controller of the Raspberry Pi. This is implemented in the class CDMAChannel
.
CDMAChannel
#include <circle/dmachannel.h>
-
class CDMAChannel
-
CDMAChannel::CDMAChannel(unsigned nChannel, CInterruptSystem *pInterruptSystem = 0)
Creates an instance of
CDMAChannel
and allocates a channel of the platform DMA controller.nChannel
must beDMA_CHANNEL_NORMAL
(normal DMA engine),DMA_CHANNEL_LITE
(lite (or normal) DMA engine),DMA_CHANNEL_EXTENDED
(“large address” DMA4 engine, on Raspberry Pi 4 only) or an explicit channel number (0-15).pInterruptSystem
is a pointer to the instance ofCInterruptSystem
and is only needed for interrupt operation.
-
void CDMAChannel::SetupMemCopy(void *pDestination, const void *pSource, size_t nLength, unsigned nBurstLength = 0, boolean bCached = TRUE)
Setup a DMA memory copy transfer from
pSource
topDestination
with lengthnLength
.nBurstLength
> 0 increases the speed, but may congest the system bus.bCached
determines, if the source and destination address ranges are in cached memory.
-
void CDMAChannel::SetupIORead(void *pDestination, u32 nIOAddress, size_t nLength, TDREQ DREQ)
Setup a DMA read transfer from the I/O port
nIOAddress
topDestination
with lengthnLength
.DREQ
paces the transfer from these devices:
DREQSourceNone (no wait)
DREQSourceEMMC
DREQSourcePCMRX
DREQSourceSMI
DREQSourceSPIRX
DREQSourceUARTRX
-
void CDMAChannel::SetupIOWrite(u32 nIOAddress, const void *pSource, size_t nLength, TDREQ DREQ)
Setup a DMA write transfer to the I/O port
nIOAddress
frompSource
with lengthnLength
.DREQ
paces the transfer to these devices:
DREQSourceNone (no wait)
DREQSourceEMMC
DREQSourcePCMTX
DREQSourcePWM
DREQSourcePWM1 (on Raspberry Pi 4 only)
DREQSourceSMI
DREQSourceSPITX
DREQSourceUARTTX
-
void CDMAChannel::SetupMemCopy2D(void *pDestination, const void *pSource, size_t nBlockLength, unsigned nBlockCount, size_t nBlockStride, unsigned nBurstLength = 0)
Setup a 2D DMA memory copy transfer of
nBlockCount
blocks ofnBlockLength
length frompSource
topDestination
. SkipnBlockStride
bytes after each block on destination. Source is continuous. The destination cache, if any, is not touched.nBurstLength
> 0 increases speed, but may congest the system bus. This method can be used to copy data to the framebuffer and is not supported withDMA_CHANNEL_LITE
.
-
void CDMAChannel::SetCompletionRoutine(TDMACompletionRoutine *pRoutine, void *pParam)
Sets a DMA completion routine for interrupt operation.
pRoutine
is called, when the transfer is completed.pParam
is a user parameter, which is handed over to the completion routine.TDMACompletionRoutine
has the following prototype:
void TDMACompletionRoutine (unsigned nChannel, boolean bStatus, void *pParam);
nChannel
is the channel number. bStatus
is TRUE
, if the transfer completed successfully.
-
void CDMAChannel::Start(void)
Starts the DMA transfer, which has been setup before.
-
boolean CDMAChannel::Wait(void)
Waits for the completion of the DMA transfer (for synchronous non-interrupt operation without completion routine). Returns
TRUE
, if the transfer was successful.
-
boolean CDMAChannel::GetStatus(void)
Returns
TRUE
, if the last completed transfer was successful.
DMA buffers
#include <circle/synchronize.h>
-
DMA_BUFFER(type, name, num)
Defines a buffer with
name
andnum
elements oftype
to be used for DMA transfers.See doc/dma-buffer-requirements.txt for more information on DMA buffers.
Cache maintenance
#include <circle/synchronize.h>
-
void CleanAndInvalidateDataCacheRange(uintptr nAddress, size_t nLength)
Cleans and invalidates a memory range in the data cache.
GPIO access
This section presents the Circle classes, which implement digital input/output operations, using the pins exposed on the 40-pin GPIO (General Purpose Input/Output) header of the Raspberry Pi (26-pin on older models). This covers writing and reading a single or all exposed GPIO pin(s), providing GPIO clocks for different purposes (e.g. for Pulse Width Modulation (PWM) output), triggering interrupts from GPIO pins, using I2C and SPI interfaces, and switching the (green) Act LED.
Please see these documents for a description of the GPIO hardware:
BCM2835 ARM Peripherals (for Raspberry Pi 1 and Zero)
BCM2711 ARM Peripherals (for Raspberry Pi 4)
The first document is also valid for the Raspberry Pi 2, 3 and Zero 2 with some modifications (e.g. I/O base address).
Important
The Circle documentation (including all READMEs) uses SoC (BCM) numbers (0-53), when referring to specific GPIO pins. These numbers are different from the physical pin position numbers (1-40) on the GPIO header. Please see pinout.xyz for the mapping of SoC numbers to the header position.
CGPIOPin
This class encapsulates a GPIO pin, which can be read, write or inverted. A GPIO pin can trigger an interrupt, when a specific GPIO event occurs.
#include <circle/gpiopin.h>
-
class CGPIOPin
-
GPIO_PINS
Number of available GPIO pins (54).
Initialization
-
CGPIOPin::CGPIOPin(void)
Default constructor. Object must be initialized afterwards using
AssignPin()
,SetMode()
and optionallySetPullMode()
.
-
CGPIOPin::CGPIOPin(unsigned nPin, TGPIOMode Mode, CGPIOManager *pManager = 0)
Creates and initializes a
CGPIOPin
instance for GPIO pin numbernPin
, set pin modeMode
.pManager
must be specified only, if this pin will trigger interrupts (IRQ).nPin
can have a numeric value (0-53) or these special values:GPIOPinAudioLeft (GPIO pin, which gates the left PWM audio channel)
GPIOPinAudioRight (GPIO pin, which gates the right PWM audio channel)
Mode
can have these values:GPIOModeInput
GPIOModeOutput
GPIOModeInputPullUp
GPIOModeInputPullDown
GPIOModeAlternateFunction0
GPIOModeAlternateFunction1
GPIOModeAlternateFunction2
GPIOModeAlternateFunction3
GPIOModeAlternateFunction4
GPIOModeAlternateFunction5
-
void CGPIOPin::AssignPin(unsigned nPin)
Assigns a GPIO pin number to the object. To be used together with the default constructor and
SetMode()
. SeeCGPIOPin::CGPIOPin()
for the possible values fornPin
.
-
void CGPIOPin::SetMode(TGPIOMode Mode, boolean bInitPin = TRUE)
Sets GPIO pin to
Mode
. SeeCGPIOPin::CGPIOPin()
for the possible values. IfbInitPin
isTRUE
, this method initializes the pull-up/down mode and output level (LOW) too. To be used together with the default constructor andAssignPin()
or for dynamic changes of the direction for input/output pins.
Input / Output
-
void CGPIOPin::Write(unsigned nValue)
Sets the GPIO pin to
nValue
(output), which can beLOW
(0) orHIGH
(1).
-
unsigned CGPIOPin::Read(void) const
Returns the value, read from the GPIO pin (input). Can be
LOW
(0) orHIGH
(1).
-
static void CGPIOPin::WriteAll(u32 nValue, u32 nMask)
Sets the GPIO pins 0-31 at once.
nValue
specifies the levels of GPIO pins 0-31 in the respective bits to be written, wherenMask
is a bit mask for the written value. Only those GPIO pins are affected, for which the respective bit is set innMask
. The other pins are not touched.
Interrupts
A GPIO pin can trigger an interrupt (IRQ) under certain conditions. The CGPIOPin
object must be initialized with a pointer to an instance of the class CGPIOManager
for this purpose. There is maximal one instance of CGPIOManager
in the system.
-
void CGPIOPin::ConnectInterrupt(TGPIOInterruptHandler *pHandler, void *pParam, boolean bAutoAck = TRUE)
Connects the interrupt handler function
pHandler
to the GPIO pin, to be called on a GPIO event.pParam
is a user parameter, which will be handed over to the interrupt handler. IfbAutoAck
is TRUE, the GPIO event detect status will be automatically acknowledged, when the interrupt occurs. Otherwise, the interrupt handler must callAcknowledgeInterrupt()
. The GPIO interrupt handler has the following prototype:
void TGPIOInterruptHandler (void *pParam);
-
void CGPIOPin::DisconnectInterrupt(void)
Disconnects the interrupt handler from the GPIO pin. The interrupt source(s) must be disabled before using
DisableInterrupt()
andDisableInterrupt2()
, if they were enabled before.
-
void CGPIOPin::EnableInterrupt(TGPIOInterrupt Interrupt)
Enables a specific event condition to trigger an interrupt for this GPIO pin.
Interrupt
can be:GPIOInterruptOnRisingEdge
GPIOInterruptOnFallingEdge
GPIOInterruptOnHighLevel
GPIOInterruptOnLowLevel
GPIOInterruptOnAsyncRisingEdge
GPIOInterruptOnAsyncFallingEdge
-
void CGPIOPin::DisableInterrupt(void)
Disables a previously enabled event condition from triggering an interrupt.
-
void CGPIOPin::EnableInterrupt2(TGPIOInterrupt Interrupt)
Same function as
EnableInterrupt()
for a second interrupt source.
CGPIOPinFIQ
This class encapsulates a special GPIO pin, which is using the FIQ (Fast Interrupt Request) to handle GPIO interrupts with low latency. There is only one GPIO pin of this type allowed in the system.
#include <circle/gpiopinfiq.h>
CGPIOPinFIQ
is derived from CGPIOPin
and inherits its methods. For initialization it provides this special constructor:
-
CGPIOPinFIQ::CGPIOPinFIQ(unsigned nPin, TGPIOMode Mode, CInterruptSystem *pInterrupt)
The parameters are the same as for
CGPIOPin::CGPIOPin()
, with one exception:pInterrupt
is a pointer the single interrupt system object in the system. ACGPIOPinFIQ
object does not need an instance ofCGPIOManager
to generate interrupts.
CGPIOManager
This class implements an interrupt multiplexer for CGPIOPin
instances. There must be exactly one instance of CGPIOManager
in the system, if at least one GPIO pin triggers interrupts using the IRQ.
#include <circle/gpiomanager.h>
-
class CGPIOManager
-
CGPIOManager::CGPIOManager(CInterruptSystem *pInterrupt)
Creates a
CGPIOManager
instance.pInterrupt
is a pointer to the interrupt system object.
-
boolean CGPIOManager::Initialize(void)
Initializes the
CGPIOManager
object. Usually called fromCKernel::Initialize()
. ReturnsTRUE
, if the initialization was successful.
CGPIOClock
A GPIO clock is a programmable digital clock generator. A Raspberry Pi computer provides several of these clocks. Their output is used for special system purposes (e.g. for the PWM and PCM / I2S devices) or can be directly connected to some GPIO pins. GPIO clocks are driven by an internal clock source with a specific clock frequency.
#include <circle/gpioclock.h>
-
class CGPIOClock
-
CGPIOClock::CGPIOClock(TGPIOClock Clock, TGPIOClockSource Source = GPIOClockSourceUnknown)
Creates a
CGPIOClock
instance for GPIO clockClock
with clock sourceSource
.Clock
can be:Clock
Connected to
GPIOClock0
GPIO4 (ALT0) or GPIO20 (ALT5)
GPIOClock1
GPIO5 (ALT0) or GPIO21 (ALT5), Raspberry Pi 4 only
GPIOClock2
GPIO6 (ALT0)
GPIOClockPCM
PCM / I2S device
GPIOClockPWM
PWM device
The respective GPIO pin has to be set to the given
GPIOModeAlternateFunctionN
(ALTn), using aCGPIOPin
object, so that the signal can be accessed at the GPIO header.Source
can be:Source
Raspberry Pi 1-3
Raspberry Pi 4
GPIOClockSourceOscillator
19.2 MHz
54 MHz
GPIOClockSourcePLLC
1000 MHz (varies)
1000 MHz (may vary)
GPIOClockSourcePLLD
500 MHz
750 MHz
GPIOClockSourceHDMI
216 MHz
unused
If
Source
is set toGPIOClockSourceUnknown
, the clock source is selected automatically, whenStartRate()
is called.
-
void CGPIOClock::Start(unsigned nDivI, unsigned nDivF = 0, unsigned nMASH = 0)
Starts the clock using the given integer divider
nDivI
(1-4095). The MASH modes withnDivF > 0
are described in the BCM2835 ARM Peripherals document.
-
boolean CGPIOClock::StartRate(unsigned nRateHZ)
Starts the clock with the given target frequency
nRateHZ
in Hertz. Assigns the clock source automatically. ReturnsFALSE
, if the requested rate cannot be generated.
-
void CGPIOClock::Stop(void)
Stops the clock.
CPWMOutput
This class provides access to the Pulse Width Modulator (PWM) device, which can be used to generate (pseudo) analog signals on the GPIO pins 18 and 19 (two channels). These pins have to be set to GPIOModeAlternateFunction5
using the class CGPIOPin
for that purpose.
#include <circle/pwmoutput.h>
-
class CPWMOutput
-
CPWMOutput::CPWMOutput(TGPIOClockSource Source, unsigned nDivider, unsigned nRange, boolean bMSMode)
Creates a
CPWMOutput
object with clock sourceSource
and the dividernDivider
(equivalent tonDivI
, 1-4095). SeeCGPIOClock
for these parameters. For the parametersnRange
(Range) andbMSMode
(M/S mode) see the BCM2835 ARM Peripherals document.
-
void CPWMOutput::Start(void)
Starts the PWM clock and device.
-
void CPWMOutput::Stop(void)
Stops the PWM clock and device.
-
void CPWMOutput::Write(unsigned nChannel, unsigned nValue)
Write
nValue
(0-Range) to PWM channelnChannel
(1 or 2).
-
PWM_CHANNEL1
-
PWM_CHANNEL2
Macros to be used for the
nChannel
parameter.
CI2CMaster
This class is a driver for the I2C master devices of the Raspberry Pi computer. The GPIO pin mapping for the I2C master devices is as follows:
nDevice |
nConfig 0 (SDA SCL) |
nConfig 1 (SDA SCL) |
Raspberry Pi boards |
---|---|---|---|
0 |
GPIO0 GPIO1 |
Rev. 1 |
|
1 |
GPIO2 GPIO3 |
All other |
|
2 |
None |
||
3 |
GPIO2 GPIO3 |
GPIO4 GPIO5 |
Raspberry Pi 4 only |
4 |
GPIO6 GPIO7 |
GPIO8 GPIO9 |
Raspberry Pi 4 only |
5 |
GPIO10 GPIO11 |
GPIO12 GPIO13 |
Raspberry Pi 4 only |
6 |
GPIO22 GPIO23 |
Raspberry Pi 4 only |
The Read()
and Write()
methods (see below) may return the following error codes as a negative value:
Value |
Description |
---|---|
I2C_MASTER_INALID_PARM |
Invalid parameter |
I2C_MASTER_ERROR_NACK |
Received a NACK |
I2C_MASTER_ERROR_CLKT |
Received clock stretch timeout |
I2C_MASTER_DATA_LEFT |
Not all data has been sent / received |
#include <circle/i2cmaster.h>
-
class CI2CMaster
-
CI2CMaster::CI2CMaster(unsigned nDevice, boolean bFastMode = FALSE, unsigned nConfig = 0)
Creates a
CI2CMaster
object for I2C masternDevice
(0-6), with configurationnConfig
(0 or 1). See the mapping above for these parameters. The default I2C clock is 100 KHz or 400 KHz, ifbFastMode
isTRUE
. This can be modified withSetClock()
for a specific transfer.
-
boolean CI2CMaster::Initialize(void)
Initializes the
CI2CMaster
object. Usually called fromCKernel::Initialize()
. ReturnsTRUE
, if the initialization was successful.
-
void CI2CMaster::SetClock(unsigned nClockSpeed)
Modifies the default clock before a specific transfer.
nClockSpeed
is the wanted I2C clock frequency in Hertz.
-
int CI2CMaster::Read(u8 ucAddress, void *pBuffer, unsigned nCount)
Reads
nCount
bytes from the I2C slave device with addressucAddress
intopBuffer
. Returns the number of read bytes or < 0 on failure. See the error codes above.
-
int CI2CMaster::Write(u8 ucAddress, const void *pBuffer, unsigned nCount)
Writes
nCount
bytes to the I2C slave device with addressucAddress
frompBuffer
. Returns the number of written bytes or < 0 on failure. See the error codes above.
CI2CSlave
This class is a driver for the I2C slave device. The GPIO pin mapping is as follows:
Raspberry Pi |
SDA |
SCL |
---|---|---|
1-3, Zero |
GPIO18 |
GPIO19 |
4 |
GPIO10 |
GPIO11 |
#include <circle/i2cslave.h>
-
class CI2CSlave
-
CI2CSlave::CI2CSlave(u8 ucAddress)
Creates the
CI2CSlave
object and assigns the I2C addressucAddress
.
-
boolean CI2CSlave::Initialize(void)
Initializes the
CI2CSlave
object. Usually called fromCKernel::Initialize()
. ReturnsTRUE
, if the initialization was successful.
CSPIMaster
The class CSPIMaster
is a driver for SPI master devices, with these features:
SPI non-AUX devices only
Standard mode (3-wire) only
Chip select lines (CE0, CE1) are active low
Polled operation only
The GPIO pin mapping is as follows:
nDevice |
MISO |
MOSI |
SCLK |
CE0 |
CE1 |
Support |
---|---|---|---|---|---|---|
0 |
GPIO9 |
GPIO10 |
GPIO11 |
GPIO8 |
GPIO7 |
All boards |
1 |
class CSPIMasterAUX |
|||||
2 |
None |
|||||
3 |
GPIO1 |
GPIO2 |
GPIO3 |
GPIO0 |
GPIO24 |
Raspberry Pi 4 only |
4 |
GPIO5 |
GPIO6 |
GPIO7 |
GPIO4 |
GPIO25 |
Raspberry Pi 4 only |
5 |
GPIO13 |
GPIO14 |
GPIO15 |
GPIO12 |
GPIO26 |
Raspberry Pi 4 only |
6 |
GPIO19 |
GPIO20 |
GPIO21 |
GPIO18 |
GPIO27 |
Raspberry Pi 4 only |
GPIO0 and GPIO1 are normally reserved for the ID EEPROM of hat boards.
#include <circle/spimaster.h>
-
class CSPIMaster
-
CSPIMaster::CSPIMaster(unsigned nClockSpeed = 500000, unsigned CPOL = 0, unsigned CPHA = 0, unsigned nDevice = 0)
Creates an
CSPIMaster
instance for access to SPI masternDevice
(see table above), with default SPI clock frequencynClockSpeed
in Hertz, clock polarityCPOL
(0 or 1) and clock phaseCPHA
(0 or 1).
-
boolean CSPIMaster::Initialize(void)
Initializes the SPI master. Usually called from
CKernel::Initialize()
. ReturnsTRUE
, if initialization was successful.
-
void CSPIMaster::SetClock(unsigned nClockSpeed)
Modifies the default SPI clock frequency before a specific transfer.
nClockSpeed
is the SPI clock frequency in Hertz. This method is not protected by an internal spin lock for multi-core operation.
-
void CSPIMaster::SetMode(unsigned CPOL, unsigned CPHA)
Modifies the default clock polarity / phase before a specific transfer.
CPOL
is the clock polarity (0 or 1) andCPHA
is the clock phase (0 or 1). These parameters must match the SPI slave settings. This method is not protected by an internal spin lock for multi-core operation.
-
void CSPIMaster::SetCSHoldTime(unsigned nMicroSeconds)
Sets the additional time, CE# stays active after the transfer. The set value is valid for the next transfer only. Normally CE# goes inactive very soon after the transfer, this sets the additional time, CE# stays active.
-
int CSPIMaster::Read(unsigned nChipSelect, void *pBuffer, unsigned nCount)
Reads
nCount
bytes intopBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 orChipSelectNone
). Returns the number of read bytes or < 0 on failure.
-
int CSPIMaster::Write(unsigned nChipSelect, const void *pBuffer, unsigned nCount)
Writes
nCount
bytes frompBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 orChipSelectNone
). Returns the number of written bytes or < 0 on failure.
-
int CSPIMaster::WriteRead(unsigned nChipSelect, const void *pWriteBuffer, void *pReadBuffer, unsigned nCount)
Simultaneous writes and reads
nCount
bytes frompWriteBuffer
and topReadBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 orChipSelectNone
). Returns the number of transferred bytes or < 0 on failure.
CSPIMasterAUX
The class CSPIMasterAUX
is a polling driver for the auxiliary SPI master (SPI1). The GPIO pin mapping is as follows:
MISO |
MOSI |
SCLK |
CE0 |
CE1 |
CE2 |
---|---|---|---|---|---|
GPIO19 |
GPIO20 |
GPIO21 |
GPIO18 |
GPIO17 |
GPIO16 |
The CE# signals are active low.
#include <circle/spimasteraux.h>
-
class CSPIMasterAUX
-
CSPIMasterAUX::CSPIMasterAUX(unsigned nClockSpeed = 500000)
Creates a
CSPIMasterAUX
object. Sets the default SPI clock frequency tonClockSpeed
in Hertz.
-
boolean CSPIMasterAUX::Initialize(void)
Initializes the SPI1 AUX master. Usually called from
CKernel::Initialize()
. ReturnsTRUE
, if initialization was successful.
-
void CSPIMasterAUX::SetClock(unsigned nClockSpeed)
Modifies the default SPI clock frequency before a specific transfer.
nClockSpeed
is the SPI clock frequency in Hertz. This method is not protected by an internal spin lock for multi-core operation.
-
int CSPIMasterAUX::Read(unsigned nChipSelect, void *pBuffer, unsigned nCount)
Reads
nCount
bytes intopBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 or 2). Returns the number of read bytes or < 0 on failure.
-
int CSPIMasterAUX::Write(unsigned nChipSelect, const void *pBuffer, unsigned nCount)
Writes
nCount
bytes frompBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 or 2). Returns the number of written bytes or < 0 on failure.
-
int CSPIMasterAUX::WriteRead(unsigned nChipSelect, const void *pWriteBuffer, void *pReadBuffer, unsigned nCount)
Simultaneous writes and reads
nCount
bytes frompWriteBuffer
and topReadBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 or 2). Returns the number of transferred bytes or < 0 on failure.
CSPIMasterDMA
The class CSPIMasterDMA
is a driver for the SPI0 master device. It implements an asynchronous DMA operation. Optionally one can do synchronous polling transfers (e.g. for small amounts of data). The GPIO pin mapping of the SPI0 master device is as follows:
MISO |
MOSI |
SCLK |
CE0 |
CE1 |
---|---|---|---|---|
GPIO9 |
GPIO10 |
GPIO11 |
GPIO8 |
GPIO7 |
#include <circle/spimasterdma.h>
-
class CSPIMasterDMA
-
CSPIMasterDMA::CSPIMasterDMA(CInterruptSystem *pInterruptSystem, unsigned nClockSpeed = 500000, unsigned CPOL = 0, unsigned CPHA = 0, boolean bDMAChannelLite = TRUE)
Creates a
CSPIMasterDMA
object. Sets the default SPI clock frequency tonClockSpeed
in Hertz, the clock polarity toCPOL
(0 or 1) and the clock phase toCPHA
(0 or 1).pInterruptSystem
is a pointer to the interrupt system object. SetbDMAChannelLite
toFALSE
for very high speeds or transfer sizes >= 64K.
-
boolean CSPIMasterDMA::Initialize(void)
Initializes the SPI0 master. Usually called from
CKernel::Initialize()
. ReturnsTRUE
, if initialization was successful.
-
void CSPIMasterDMA::SetClock(unsigned nClockSpeed)
Modifies the default SPI clock frequency before a specific transfer.
nClockSpeed
is the SPI clock frequency in Hertz.
-
void CSPIMasterDMA::SetMode(unsigned CPOL, unsigned CPHA)
Modifies the default clock polarity / phase before a specific transfer.
CPOL
is the clock polarity (0 or 1) andCPHA
is the clock phase (0 or 1). These parameters must match the SPI slave settings.
-
void CSPIMasterDMA::SetCompletionRoutine(TSPICompletionRoutine *pRoutine, void *pParam)
Sets a completion routine
pRoutine
to be called, when the next transfer completes.pParam
is a user parameter, which is handed over to the completion routine. The prototype of the completion routine looks like this:
void TSPICompletionRoutine (boolean bStatus, void *pParam);
bStatus
is TRUE
on success.
-
void CSPIMasterDMA::StartWriteRead(unsigned nChipSelect, const void *pWriteBuffer, void *pReadBuffer, unsigned nCount)
Starts a simultaneous write and read transfer of
nCount
bytes frompWriteBuffer
and topReadBuffer
. Chip selectnChipSelect
(CE#, 0, 1 orChipSelectNone
) will be activated during the transfer. The buffers must be aligned to the size of a data-cache-line (see DMA buffers).
-
int CSPIMasterDMA::WriteReadSync(unsigned nChipSelect, const void *pWriteBuffer, void *pReadBuffer, unsigned nCount)
Simultaneous writes and reads
nCount
bytes frompWriteBuffer
and topReadBuffer
. Activates chip selectnChipSelect
(CE#, 0, 1 orChipSelectNone
). Returns the number of transferred bytes or < 0 on failure. Synchronous (polled) operation for small amounts of data.
CSMIMaster
The class CSMIMaster
is a driver for the Secondary Memory Interface (SMI) device of the Raspberry Pi. It supports the following features:
Drives any combination of SMI data lines (GPIO8 to GPIO25)
May also drive SMI address lines (GPIO0 to GPIO5)
Does not use SOE / SWE lines on GPIO6 / GPIO7
Read / Write operation in direct mode, or Write-only in DMA mode
Note
One must first call CSMIMaster::SetupTiming()
with suitable timing information. The device bank to use and the address to assert on the SAx lines may then optionally be set with CSMIMaster::SetDeviceAndAddress()
. Then direct mode may be used with CSMIMaster::Read()
or CSMIMaster::Write()
, or for DMA mode one must first call CSMIMaster::SetupDMA()
with a suitable buffer, then CSMIMaster::WriteDMA()
to flush the buffer to SMI.
#include <circle/smimaster.h>
-
class CSMIMaster
-
CSMIMaster::CSMIMaster(unsigned nSDLinesMask = 0x3FFFF, boolean bUseAddressPins = TRUE)
Creates a
CSMIMaster
object. There can be only one.nSDLinesMask
is a bit mask, which determines which SDx lines should be driven. For example(1 << 0) | (1 << 5)
for SD0 (GPIO8) and SD5 (GPIO13).bUseAddressPins
enables the use of the address pins GPIO0 to GPIO5, if it is set toTRUE
.
-
unsigned CSMIMaster::GetSDLinesMask(void)
Returns the
nSDLinesMask
, handed over to the constructor.
-
void CSMIMaster::SetupTiming(TSMIDataWidth Width, unsigned nCycle_ns, unsigned nSetup, unsigned nStrobe, unsigned nHold, unsigned nPace, unsigned nDevice = 0)
Sets up the SMI cycle.
nWidth
is the length of the data bus (see below).nCycle_ns
is the clock period for the setup/strobe/hold cycle (in nanoseconds).nSetup
is the setup time, that is used to decode the address value (in units ofnCycle_ns
).nStrobe
is the width of the strobe pulse, that triggers the transfer (in units ofnCycle_ns
).nHold
is the hold time, that keeps the signals stable after the transfer (in units ofnCycle_ns
).nPace
is the pace time in between two cycles (in units ofnCycle_ns
).nDevice
is the settings bank to use (0 .. 3).
-
enum TSMIDataWidth
Values for specifying the width of the SMI data bus:
SMI8Bits
SMI9Bits
SMI16Bits
SMI18Bits
-
void CSMIMaster::SetupDMA(void *pDMABuffer, unsigned nLength)
Sets up DMA for (potentially multiple) SMI cycles of data from the buffer
pDMABuffer
(must be DMA-aligned).nLength
is the length of the buffer in bytes.
-
void CSMIMaster::SetDeviceAndAddress(unsigned nDevice, unsigned nAddr)
Defines the device and address to use for the next Read/Write operation.
nDevice
is the settings bank to use (0 .. 3).nAddr
is the value to be asserted on the address pins SAx.
-
unsigned CSMIMaster::Read(void)
Issues a single SMI read cycle from the SDx lines, and returns the read value.
-
void CSMIMaster::Write(unsigned nValue)
Issues a single SMI write cycle, i.e. writes the value
nValue
to the (enabled) SDx lines.
-
void CSMIMaster::WriteDMA(boolean bWaitForCompletion)
Triggers a DMA transfer of a few cycles with the buffer/length specified in
SetupDMA()
.bWaitForCompletion
specifies whether to wait for DMA completion before returning.
CActLED
This class switches the (green) Act(ivity) LED on or off. It automatically determines the Raspberry Pi model to use the right LED pin for the model.
#include <circle/actled.h>
-
class CActLED
-
CActLED::CActLED(boolean bSafeMode = FALSE)
Creates the
CActLED
object. Safe mode works with LEDs connected to GPIO expander and chain boot, but is not as quick.
Multi-core support
Beginning with the Raspberry Pi 2, four cores are provided by a Cortex-A CPU. Circle distinguishes between the primary core 0 and the secondary cores 1 to 3 in a way, that all system operations including interrupt handling are running on the primary core 0. The secondary cores are free to be used by the application. This allows to implement time-critical or time-consuming operations on the secondary cores, without being disturbed by interrupts or other system functions. The optional scheduler and all tasks are running on core 0 too (see Multitasking).
Circle supports multi-core applications by handling the start-up of the secondary cores with the class CMultiCoreSupport, with the synchronization class CSpinLock and with Memory barriers.
The system option ARM_ALLOW_MULTI_CORE
has to be defined to use multi-core support with the class CMultiCoreSupport
. For performance reasons this system option should not be defined for single core applications.
Further information on using the multi-core support is available in the file doc/multicore.txt.
The sample programs 17-fractal and 26-cpustress can be build with multi-core support. A more complex multi-core example is the project MiniSynth Pi.
CMultiCoreSupport
#include <circle/multicore.h>
-
class CMultiCoreSupport
If you want to use the secondary CPU cores in your application, you have to define a user class, which is derived from the class CMultiCoreSupport
.
-
CMultiCoreSupport::CMultiCoreSupport(CMemorySystem *pMemorySystem)
Creates the instance of
CMultiCoreSupport
. Must be invoked in the first place of the initializer list of the defined user class. The parameterpMemorySystem
must be set toCMemorySystem::Get()
, which can be included from<circle/memory.h>
.
-
boolean CMultiCoreSupport::Initialize(void)
Initializes the multi-core support and starts the secondary cores. It is important, that this method is called, when the other system initialization is already done. Normally it is invoked at the last method in
CKernel::Run()
.
-
virtual void CMultiCoreSupport::Run(unsigned nCore) = 0
Overload this virtual method to define the entry for the secondary cores (1 to 3) into your application. It is invoked three times (once on each secondary core) with
nCore
being the number of the executing CPU core (1, 2 or 3).
Important
When a secondary core returns from Run()
, the CPU core is automatically halted and will sleep. For unused cores you can simply return from this method.
Note
This method is not executed from the primary CPU core 0 by default. If you want to handle all CPU cores at the same place, you have to explicitly call the Run()
method of your user defined multi-core class from CKernel::Run()
with the parameter 0.
-
static unsigned CMultiCoreSupport::ThisCore(void)
Returns the number of the CPU core (0, 1, 2 or 3), which called this method.
-
static void CMultiCoreSupport::HaltAll(void)
In a multi-core environment this method halts all CPU cores. The current execution will be interrupted using an Inter-Processor Interrupt (IPI) and each core calls the
halt()
function in turn.
-
static void CMultiCoreSupport::SendIPI(unsigned nCore, unsigned nIPI)
Sends an Inter-Processor Interrupt (IPI) with the number
nIPI
to the corenCore
(0, 1, 2 or 3). If this technique is used for application purposes,nIPI
can have a user defined value fromIPI_USER
toIPI_MAX
.
-
virtual void CMultiCoreSupport::IPIHandler(unsigned nCore, unsigned nIPI)
Overload this virtual method to receive Inter-Processor Interrupts (IPI) from other CPU cores.
nCore
is the number of the CPU core, which received the IPI and which is executingIPIHandler()
.nIPI
is the IPI number specified in the call toCMultiCoreSupport::SendIPI()
.
Important
Be sure to pass calls to this method further to CMultiCoreSupport::IPIHandler()
with the same parameters, if nIPI < IPI_USER
. Otherwise the CMultiCoreSupport::HaltAll()
method will not work, which is also invoked on a system panic condition (abort exception, assertion failed).
CPU clock rate management
Most Raspberry Pi models require a CPU clock rate management by the bare metal application to reach the maximum performance. This management continuously measures the current temperature of the CPU (actually the SoC) and regulates the clock rate of the ARM CPU, so that it is decreased, when the temperature is getting too high.
The absolute maximum of the allowed CPU temperature is 85 degrees Celsius. The firmware automatically ensures, that this limit is not exceeded. If the temperature comes near to this value, the firmware shows a warning icon in the upper right corner of the screen. Please read the Frequency management and thermal control documentation page to get more information on this.
The different Raspberry Pi models allow different maximum CPU clock rates and the the frequency of the ARM CPU, which is set after boot, is also different:
Raspberry Pi |
Maximum CPU clock rate |
Boot CPU clock rate |
Remarks |
---|---|---|---|
1 |
700 MHz |
700 MHz |
No management required |
2 |
900 MHz |
600 MHz |
|
Zero |
1000 MHz |
700 MHz |
|
Zero 2 |
1000 MHz |
600 MHz |
|
3 Model B |
1200 MHz |
600 MHz |
|
3 Model A+/B+ |
1400 MHz |
600 MHz |
|
4 |
1500 MHz |
600 MHz |
Rev. 1.4: 1800 MHz |
400 |
1800 MHz |
600 MHz |
Head sink included |
Circle uses the class CCPUThrottle
to implement a CPU clock rate management, which is described below. The sample program 26-cpustress demonstrates its usage.
Important
After boot the CPU clock rate of the ARM CPU is not set to the allowed maximum on most Raspberry Pi models. Without further action, the bare metal application will not operate with maximum performance.
If you need the maximum performance at any time in your application and cannot handle, when the CPU is clocked down, you may need a head sink and/or fan installed.
CCPUThrottle
should not be used together with code doing I2C or SPI transfers. Because clock rate changes to the CPU clock may also effect the CORE clock, this could result in changing transfer speeds.
Note
To keep the CPU performance at the maximum level, it is possible to use a Case Fan, which is especially available for the official Raspberry Pi 4 case. This fan has a control line, which has to be connected to a GPIO pin. To use such a fan with the class CCPUThrottle
, you have to add the option gpiofanpin=PIN
to the file cmdline.txt, where PIN is the GPIO pin number (SoC number, not header position) to which the control line of the fan is connected. The CPU speed is not throttled, when this option is used.
CCPUThrottle
#include <circle/cputhrottle.h>
-
class CCPUThrottle
-
CCPUThrottle::CCPUThrottle(TCPUSpeed InitialSpeed = CPUSpeedUnknown)
Creates the class
CCPUThrottle
.InitialSpeed
is the CPU speed to be set initially, with these possible values:CPUSpeedLow
CPUSpeedMaximum
CPUSpeedUnknown
If
CPUSpeedUnknown
is selected as initial speed and the parameterfast=true
is set in the file cmdline.txt, the resulting setting will beCPUSpeedMaximum
, orCPUSpeedLow
if not set.
-
static CCPUThrottle *CCPUThrottle::Get(void)
Returns a pointer to the only
CCPUThrottle
object in the system (if any).
-
boolean CCPUThrottle::IsDynamic(void) const
Returns if CPU clock rate change is supported. Other Methods can be called in any case, but may be nop’s or return invalid values, if
IsDynamic()
returnsFALSE
.
-
unsigned CCPUThrottle::GetClockRate(void) const
Returns the current CPU clock rate in Hz or zero on failure.
-
unsigned CCPUThrottle::GetMinClockRate(void) const
Returns the minimum CPU clock rate in Hz.
-
unsigned CCPUThrottle::GetMaxClockRate(void) const
Returns the maximum CPU clock rate in Hz.
-
unsigned CCPUThrottle::GetTemperature(void) const
Returns the current CPU (SoC) temperature in degrees Celsius or zero on failure.
-
unsigned CCPUThrottle::GetMaxTemperature(void) const
Returns the maximum CPU (SoC) temperature in degrees Celsius.
-
TCPUSpeed CCPUThrottle::SetSpeed(TCPUSpeed Speed, boolean bWait = TRUE)
Sets the CPU speed.
Speed
selects the speed to be set and overwrites the initial value. Possible values are:CPUSpeedLow
CPUSpeedMaximum
bWait
must beTRUE
to wait for new clock rate to settle before return. Returns the previous setting orCPUSpeedUnknown
on error.
-
boolean CCPUThrottle::SetOnTemperature(void)
Sets the CPU speed depending on current SoC temperature. Call this repeatedly all 2 to 5 seconds to hold the temperature down! Throttles the CPU down when the SoC temperature reaches 60 degrees Celsius Returns
TRUE
if the operation was successful.
Note
The default temperature limit of 60 degrees Celsius may be too small for continuous operation with maximum performance. The limit can be increased with the parameter socmaxtemp
in the file cmdline.txt.
-
boolean CCPUThrottle::Update(void)
Same function as
SetOnTemperature()
, but can be called as often as you want, without checking the calling interval. Additionally checks for system throttled conditions, if a system throttled handler has been registered withRegisterSystemThrottledHandler()
. ReturnsTRUE
if the operation was successful.
Important
You have to repeatedly call SetOnTemperature()
or Update()
, if you use this class!
-
void CCPUThrottle::RegisterSystemThrottledHandler(unsigned StateMask, TSystemThrottledHandler *pHandler, void *pParam = 0)
Registers the callback
pHandler
, which is invoked fromUpdate()
, when a system throttled condition occurs, which is given inStateMask
.pParam
is any user parameter to be handed over to the callback function.StateMask
can be composed from these bit masks by or’ing them together:SystemStateUnderVoltageOccurred
SystemStateFrequencyCappingOccurred
SystemStateThrottlingOccurred
SystemStateSoftTempLimitOccurred
-
void CCPUThrottle::DumpStatus(boolean bAll = TRUE)
Dumps some information on the current CPU status to the System log. Set
bAll
toTRUE
to dump all information. Only the current clock rate and temperature will be dumped otherwise.
Firmware access
In order for a device driver to make certain settings (e.g. size of the frame buffer), it sometimes needs to communicate with the firmware, which runs on the VPU co-processor. This may be necessary from application code too, if specific settings should be made, which are not supported by Circle. The firmware can be accessed using the Mailbox property interface. This is supported in Circle by the class CBcmPropertyTags
.
Note
This Mailbox property interface wiki article does not describe all supported functions. Information on more functions can only be retrieved from the Linux source code.
Direct hardware access
Circle applications may need to directly read or write registers of hardware devices, if a driver for the respective device does not exist yet. This subsection describes the Circle support for accessing hardware registers.
Functions
#include <circle/memio.h>
-
u8 read8(uintptr nAddress)
-
u16 read16(uintptr nAddress)
-
u32 read32(uintptr nAddress)
Reads a value with the specified bit size from the memory-mapped I/O address
nAddress
and returns it.
-
void write8(uintptr nAddress, u8 uchValue)
-
void write16(uintptr nAddress, u16 usValue)
-
void write32(uintptr nAddress, u32 nValue)
Writes a value with the specified bit size to the memory-mapped I/O address
nAddress
.uchValue
,usValue
andnValue
are the respective values.
Note
An access to a memory-mapped I/O device register must normally be aligned to the access size.
Macros
The detailed definitions for the different hardware devices of the Raspberry Pi cannot be listed here. Please read the respective header file for details.
#include <circle/bcm2835.h>
This header file provides macro definitions of memory-mapped I/O addresses for all Raspberry Pi models, described in the BCM2835 ARM Peripherals document, especially:
-
ARM_IO_BASE
Base address of the 16 MB sized main memory-mapped I/O block, valid on the ARM CPU of the respective Raspberry Pi model. This address is normally used from the Circle application.
-
GPU_IO_BASE
Base address of the 16 MB sized main memory-mapped I/O block, valid on the GPU co-processor. This address is used for operations, which are executed by the GPU or connected devices (e.g. DMA controllers).
Note
A Raspberry Pi has several processing units. We only distinguish here between the ARM CPU, where the Circle application is running on, and all other processing units, where the firmware, accelerated graphics processing and more is executed. We call these processors the GPU or VPU. Please note that from the point of view of the boot order, the ARM CPU is the secondary co-processor.
-
GPU_MEM_BASE
Base address of the lower (starting at address 0x0 on the ARM CPU) 1 GB memory address range, valid on the GPU and connected devices (e.g. DMA controllers). The legacy platform DMA controller, for instance, can only access this address space for data transfers.
-
BUS_ADDRESS(address)
Converts the memory address
address
, valid on the ARM CPU, to a GPU bus address, valid on the GPU and connected devices.
#include <circle/bcm2836.h>
This header file provides macro definitions of memory-mapped I/O addresses for the Raspberry Pi 2 to 4 and compatible models, described in the ARM Quad A7 core document, especially:
-
ARM_LOCAL_BASE
Base address of the 256 MB sized local memory-mapped I/O block. A number of registers from this block are local to the respective ARM CPU core.
#include <circle/bcm2711.h>
This header file provides macro definitions of memory-mapped I/O addresses for the Raspberry Pi 4 and compatible models, described in the BCM2711 ARM Peripherals document.
I/O barriers
The following I/O barriers are especially required on the Raspberry Pi 1 and Zero. On other Raspberry Pi models they have no function.
#include <circle/synchronization.h>
-
PeripheralEntry()
If your code directly accesses memory-mapped hardware registers, you should insert this special barrier before the first access to a specific hardware device.
-
PeripheralExit()
If your code directly accesses memory-mapped hardware registers, you should insert this special barrier after the last access to a specific hardware device.
Note
Most programs would work without PeripheralEntry()
and PeripheralExit()
, but to be sure, it should be used as noted. In a few tests there have been issues on the Raspberry Pi 1, where invalid data was read from hardware registers, without these barriers inserted.
You do not need to care about this, when you access hardware devices using a Circle device driver class, because this is handled inside the driver.
Utilities
This section lists utility classes and functions, which help to implement Circle applications.
CString
#include <circle/string.h>
-
class CString
This class encapsulates a character string and allows different manipulations on it. The methods of this class are not reentrant.
-
CString::CString(const char *pString)
Creates a string object. Sets the string initially to
pString
.
-
CString::CString(const CString &rString)
Copy constructor. Creates a new string object. Sets the string initially to the value of
rString
.rString
remains unchanged.
-
CString::CString(CString &&rrString)
Move constructor. Creates a new string object. Sets the string initially to the value of
rrString
.rrString
is set to an empty string.
-
CString::operator const char*(void) const
Returns a pointer to the string buffer, which is terminated with a zero-character.
-
const char *CString::operator=(const char *pString)
Assigns a new string. Returns a pointer to the string buffer, which is terminated with a zero-character.
-
CString &CString::operator=(const CString &rString)
Assigns a new string. Returns a reference to the string object.
-
CString &CString::operator=(CString &&rrString)
Move assignment. Assigns a new string.
rrString
is set to an empty string. Returns a reference to the string object.
-
size_t CString::GetLength(void) const
Returns the length of the string in number of characters (zero for empty string).
-
int CString::Compare(const char *pString) const
Compares
pString
with the string. Returns:zero, if the strings are identical
a negative value, if the string is smaller than
pString
a positive value, if the string is greater than
pString
-
int CString::Find(char chChar) const
Searches for
chChar
in the string. Returns the zero-based index of the character or -1, if it is not found.
-
int CString::Replace(const char *pOld, const char *pNew)
Replaces all occurrences of
pOld
withpNew
in the string. Returns the number of occurrences.
-
void CString::Format(const char *pFormat, ...)
Formats a string as known from
sprintf()
. Does support only a subset of the known format specifiers:%[#][[-][0]len][.prec][l|ll]{c|d|f|i|o|p|s|u|x|X}
Field
Description
#
insert prefix 0, 0x or 0X for %o, %x or %X
-
left justify output
0
insert leading zeros
len
decimal number specifying the length of the field
.prec
decimal number specifying the precision for %f
l
type is
long
ll
type is
long long
(with STDLIB_SUPPORT >= 1 only)c
insert
char
d
insert decimal
int
,long
orlong long
(maybe with sign)f
insert
double
i
same as %d
o
insert octal
unsigned
,unsigned long
orunsigned long long
p
same as %x
s
insert string (type is
const char *
)u
insert decimal
unsigned
,unsigned long
orunsigned long long
x
insert hex
unsigned
,unsigned long
orunsigned long long
(lower case)X
insert hex
unsigned
,unsigned long
orunsigned long long
(upper case)
CPtrArray
#include <circle/ptrarray.h>
-
class CPtrArray
This class implements a dynamic array of pointers. The methods of this class are not reentrant.
-
CPtrArray::CPtrArray(unsigned nInitialSize = 100, unsigned nSizeIncrement = 100)
Creates a
CPtrArray
object with initially space fornInitialSize
elements. The memory allocation will be increased bynSizeIncrement
elements, when the array is full.
-
void *CPtrArray::operator[](unsigned nIndex) const
Returns the pointer for the array element at
nIndex
(based on zero).nIndex
must be smaller than the value returned fromGetCount()
.
CPtrList
#include <circle/ptrlist.h>
-
class CPtrList
This class implements a linked list of pointers. The methods of this class are not reentrant.
-
type TPtrListElement
Opaque type definition.
-
TPtrListElement *CPtrList::GetNext(TPtrListElement *pElement)
Returns the next element following
pElement
, or 0 if nothing follows.
-
void CPtrList::InsertBefore(TPtrListElement *pAfter, void *pPtr)
Inserts
pPtr
before the elementpAfter
, which must not be 0.
CNumberPool
#include <circle/numberpool.h>
-
class CNumberPool
This class implements an allocation pool for numbers. The methods of this class are not reentrant.
-
static const unsigned Limit = 63
Allowed maximum of an allocated number.
-
CNumberPool::CNumberPool(unsigned nMin, unsigned nMax = Limit)
Creates a number pool.
nMin
is the minimal returned number byAllocateNumber()
.nMax
is the maximal returned number.
-
unsigned CNumberPool::AllocateNumber(boolean bMustSucceed, const char *pFrom = "numpool")
Allocates a number from the number pool and returns it. If there are no more numbers available, this method returns
CNumberPool::Invalid
, ifbMustSucceed
isFALSE
, or the system halts with a panic message otherwise. This message has the prefixpFrom
.
-
void CNumberPool::FreeNumber(unsigned nNumber)
Returns
nNumber
, which has been allocated earlier, to the number pool for reuse.
Atomic memory access
#include <circle/atomic.h>
This header file defines some functions, which implement an atomic access to an aligned int
variable in memory. These functions can be useful for synchronization purposes, especially for multi-core applications, where using a spin lock would be too time consuming. All accesses to such a variable must use one of the following functions, to ensure them being atomic.
-
int AtomicGet(volatile const int *pVar)
Returns the value of the
int
variable atpVar
.
-
int AtomicSet(volatile int *pVar, int nValue)
Sets the
int
variable atpVar
tonValue
and returnsnValue
.
-
int AtomicExchange(volatile int *pVar, int nValue)
Sets the
int
variable atpVar
tonValue
and returns the previous value.
-
int AtomicCompareExchange(volatile int *pVar, int nCompare, int nValue)
Sets the
int
variable atpVar
tonValue
, if the previous value of the variable wasnCompare
, and returns the previous value of the variable.
-
int AtomicAdd(volatile int *pVar, int nValue)
Adds
nValue
to theint
variable atpVar
. Returns the result of the operation.
-
int AtomicSub(volatile int *pVar, int nValue)
Subtracts
nValue
from theint
variable atpVar
. Returns the result of the operation.
-
int AtomicIncrement(volatile int *pVar)
Increments the
int
variable atpVar
by 1. Returns the result of the operation.
-
int AtomicDecrement(volatile int *pVar)
Decrements the
int
variable atpVar
by 1. Returns the result of the operation.
C standard library functions
#include <circle/util.h>
This header file defines some functions, known from the C standard library.
Memory functions
-
void *memset(void *pBuffer, int nValue, size_t nLength)
-
void *memcpy(void *pDest, const void *pSrc, size_t nLength)
-
void *memmove(void *pDest, const void *pSrc, size_t nLength)
-
int memcmp(const void *pBuffer1, const void *pBuffer2, size_t nLength)
String functions
-
size_t strlen(const char *pString)
-
int strcmp(const char *pString1, const char *pString2)
-
int strcasecmp(const char *pString1, const char *pString2)
-
int strncmp(const char *pString1, const char *pString2, size_t nMaxLen)
-
int strncasecmp(const char *pString1, const char *pString2, size_t nMaxLen)
-
char *strcpy(char *pDest, const char *pSrc)
-
char *strncpy(char *pDest, const char *pSrc, size_t nMaxLen)
-
char *strcat(char *pDest, const char *pSrc)
-
char *strchr(const char *pString, int chChar)
-
char *strstr(const char *pString, const char *pNeedle)
-
char *strtok_r(char *pString, const char *pDelim, char **ppSavePtr)
Number conversion
-
unsigned long strtoul(const char *pString, char **ppEndPtr, int nBase)
-
unsigned long long strtoull(const char *pString, char **ppEndPtr, int nBase)
-
int atoi(const char *pString)
Other functions
#include <circle/util.h>
-
u16 bswap16(u16 usValue)
-
u32 bswap32(u32 ulValue)
Swaps the byte order of a 16- or 32-bit value.
-
int parity32(unsigned nValue)
Returns the number of 1-bits in
nValue
modulo 1.
Macros
#include <circle/macros.h>
-
PACKED
Packs a
struct
definition. The members will be stored tightly, not aligned as usual.
-
ALIGN(n)
Aligns a variable or member to a boundary of
n
in memory.
-
NORETURN
Append this to the prototype of a function, which never returns.
-
BIT(n)
Returns the bit mask
(1U << (n))
.
-
likely(exp)
-
unlikely(exp)
In time critical code this gives the compiler a hint, which result of the boolean expression
exp
is normally expected. This can result in faster code.
Debugging support
Circle provides a number of classes, functions and macros, which support the debugging of applications. This section describes the tools, which can be included in a program itself. Debugging a Circle application with an external debugger is described in doc/debug-jtag.txt and doc/debug.txt in the Circle repository.
Note
Beside the tools, which are described here, you can also use the System log to write debug messages to the screen or serial interface.
Assertions
Assertions are a common technique to insert runtime checks into the code. This is frequently used in the Circle libraries itself and is also recommended for application code. Assertions will be included in a checked build of Circle only and are ignored, when the macro symbol NDEBUG
is defined.
#include <assert.h>
-
assert(expr)
Inserts a runtime check into the code.
expr
must be a true boolean expression, otherwise the system is halted with an “Assertion failed” message, which contains the filename and the source code line of the failed assertion, and with a stack trace.
-
ASSERT_STATIC(expr)
This is a static assertion, which will be evaluated at build time. It will be placed outside of a function, e.g. to check the size of a structure definition. The compiler generates an error message, if the expression
expr
is false.
Functions
The following functions are only available, when NDEBUG
is not defined.
#include <circle/debug.h>
-
void debug_hexdump(const void *pStart, unsigned nBytes, const char *pSource = 0)
Writes a hexdump of
nBytes
, starting atpStart
to the System log.pSource
is used as prefix of the log messages (“debug” if omitted).
-
void debug_stacktrace(const uintptr *pStackPtr, const char *pSource = 0)
Writes a stack trace to the System log. This function tests 64 numbers starting at
pStackPtr
, if they point into the program code and logs them in this case.
-
void debug_click(unsigned nMask = DEBUG_CLICK_ALL)
This function can be used to debug events, which occur frequently, so that writing a log message would destroy the timing of the system. The function generates an audio click, which can be heard via the headphone jack of the Raspberry Pi. Frequent events generate a tone, very frequent events may generate a frequency, which is not hear-able.
nMask
can beDEBUG_CLICK_LEFT
,DEBUG_CLICK_RIGHT
orDEBUG_CLICK_ALL
and selects the audio channel to be used. On some Raspberry Pi models these channels may be swapped.
Note
The macro DEBUG_CLICK
must be defined, when you want to use debug_click()
. The PWM audio device cannot be used in this case.
CExceptionHandler
#include <circle/exceptionhandler.h>
-
class CExceptionHandler
This class handles abort exceptions, which occur on different program errors. The exception handler displays a stack trace and logs some important register values. An instance of this class should be added to each more complex program, which includes a
CLogger
instance too. Usually it will be added as a member toCKernel
. This class does not have methods, which can be called from application code.
CTracer
#include <circle/tracer.h>
-
class CTracer
This class can be used to trace the program execution, without changing the timing too much. The class maintains a ring buffer, which is filled with trace events and dumped later, when the execution of the critical program parts has been completed.
-
CTracer::CTracer(unsigned nDepth, boolean bStopIfFull)
Creates an instance of this class.
nDepth
is the size of the ring buffer in number of events. IfbStopIfFull
isTRUE
, the tracing stops automatically, when the ring buffer is full. Otherwise a new event overwrites the oldest event.
-
void CTracer::Start(void)
Starts the tracing and the tracing clock. Arriving events will be written to the ring buffer now.
-
void CTracer::Event(unsigned nID, unsigned nParam1 = 0, unsigned nParam2 = 0, unsigned nParam3 = 0, unsigned nParam4 = 0)
Sends an event to the tracer. Insert this into your program code, where something important happens to catch an issue.
nID
is any number, except 0, which is the stop event.nParamN
is any parameter of the event. This method is not reentrant. You have to use a spin lock, ifEvent()
may be called concurrently.
-
void CTracer::Dump(void)
Writes the entire tracing buffer to the System log. If the tracing was not stopped before, it is stopped automatically before the dump.
CLatencyTester
#include <circle/latencytester.h>
-
class CLatencyTester
This class can be used to measure the IRQ latency of the running code. The class continuously triggers an IRQ and measures the delay between the time, the IRQ was triggered and the time, the IRQ handler is called. This delay can be important for real-time applications. This is demonstrated in the sample program 40-irqlatency.
Note
The class CLatencyTester
blocks the system timer 1, which is used by the class CUserTimer
too. You can use only one of both classes at a time.
-
CLatencyTester::CLatencyTester(CInterruptSystem *pInterruptSystem)
Creates a
CLatencyTester
object.pInterruptSystem
is a pointer to the interrupt system object.
-
void CLatencyTester::Start(unsigned nSampleRateHZ)
Starts the measurement.
nSampleRateHZ
is the sample rate in Hz.
-
void CLatencyTester::Stop(void)
Stops the measurement.
-
unsigned CLatencyTester::GetMin(void) const
Returns the minimum IRQ latency in microseconds. Can be called, while the test is running.
-
unsigned CLatencyTester::GetMax(void) const
Returns the maximum IRQ latency in microseconds. Usually this is the most interesting value. Can be called, while the test is running.
-
unsigned CLatencyTester::GetAvg(void)
Returns the average IRQ latency in microseconds. Can be called, while the test is running. Please note that the accumulated IRQ latency may overrun after some time. This method will return 0xFFFFFFFFU then.
-
void CLatencyTester::Dump(void)
Writes the results to the System log.
Subsystems
This section describes the Circle subsystems. A subsystems is a group of classes, which implements services for a specific purpose, which are different from the Basic system services and are normally provided by its own library (see Libraries). Only those classes are discussed here, which are directly used by applications. All Circle classes are listed in doc/classes.txt.
The Circle project does not provide a single centralized C++ header file. Instead the header file(s), which must be included for a specific class, function or macro definition are specified in the related subsection.
Multitasking
Circle provides an optional cooperative non-preemptive scheduler, which allows to solve programming problems based on the process concept. Because in Circle there is only one flat address space with a one-to-one physical-to-virtual address mapping a process in Circle is similar to a thread. In Circle the name “task” is used instead.
Because the scheduler is optional, a Circle application can work without it. The scheduler was introduced to implement TCP/IP networking support, which required many threads of execution at the same time to be implemented even on the one-core Raspberry Pi models. Later porting the VCHIQ driver and HDMI sound support, the accelerated graphics support (Raspberry Pi 1-3 and Zero only) and Wireless LAN support had similar requirements. It can be useful to use the scheduler also for modeling complex user problems in Circle.
The scheduler library provides the following classes:
Class |
Function |
---|---|
CScheduler |
Cooperative non-preemptive scheduler |
CTask |
Representation of a thread of execution, a task |
CMutex |
Mutual exclusion (critical sections) across tasks |
CSemaphore |
Implements the well-known semaphore concept |
CSynchronizationEvent |
Synchronizes the execution of task(s) with an event |
Important
In a multi-core environment (see Multi-core support) all tasks and the scheduler run on CPU core 0.
CScheduler
This class implements a cooperative non-preemptive scheduler, which controls which task runs at a time. Because the scheduler is non-preemptive, a running task has to explicitly release the CPU by sleeping, waiting for a synchronization object (mutex, semaphore, synchronization event) or by calling CScheduler::Get()->Yield()
after a short time, so that the other tasks are able to run. This relatively simple scheduler implements the round-robin policy without task priorities (and without much overhead).
#include <circle/sched/scheduler.h>
-
class CScheduler
-
static boolean CScheduler::IsActive(void)
Returns
TRUE
if the scheduler is available in the system. The scheduler is optional in Circle.
-
static CScheduler *CScheduler::Get(void)
Returns a pointer to the only scheduler object in the system. It must not be called, if the scheduler is not available.
-
CTask *CScheduler::GetCurrentTask(void)
Returns a pointer to the
CTask
object of the currently running task.
-
CTask *CScheduler::GetTask(const char *pTaskName)
Returns a pointer to the
CTask
object of the task with the namepTaskName
or 0, if the task was not found.
-
boolean CScheduler::IsValidTask(CTask *pTask)
Returns
TRUE
, ifpTask
is referencing a CTask object of a currently known task.
-
void CScheduler::Yield(void)
Switch to the next task. The currently running task releases the CPU and the next task in round-robin order, which is not blocked, gets control.
Important
A task should call this from time to time, if it does longer calculations.
-
void CScheduler::Sleep(unsigned nSeconds)
The current task pauses execution for
nSeconds
seconds. The next ready task gets control.
-
void CScheduler::MsSleep(unsigned nMilliSeconds)
The current task pauses execution for
nMilliSeconds
milliseconds. The next ready task gets control.
-
void CScheduler::usSleep(unsigned nMicroSeconds)
The current task pauses execution for
nMicroSeconds
microseconds. The next ready task gets control.
-
void CScheduler::SuspendNewTasks(void)
Causes all new tasks to be created in a suspended state. You can achieve the same, if you set the parameter
bCreateSuspended
toTRUE
, when callingnew
for a task. Nested calls toSuspendNewTasks()
andResumeNewTasks()
are allowed.
-
void CScheduler::ResumeNewTasks(void)
Stops causing new tasks to be created in a suspended state and starts any tasks that were created suspended. Nested calls to
SuspendNewTasks()
andResumeNewTasks()
are allowed.
-
void CScheduler::ListTasks(CDevice *pTarget)
Writes a task listing to the device
pTarget
.
-
void CScheduler::RegisterTaskSwitchHandler(TSchedulerTaskHandler *pHandler)
pHandler
is called on each task switch. This method is normally used by the Linux kernel driver and Pthreads emulation. The handler is called with a pointer to theCTask
object of the task, which gets control now. The prototype of the handler is:
void TSchedulerTaskHandler (CTask *pTask);
-
void CScheduler::RegisterTaskTerminationHandler(TSchedulerTaskHandler *pHandler)
pHandler
is called, when a task terminates. This method is normally used by the Linux kernel driver and Pthreads emulation. The handler is called with a pointer to theCTask
object of the task, which terminates. SeeRegisterTaskSwitchHandler()
for the prototype of the handler.
CTask
Derive this class, define the Run()
method to implement your own task and call new
on it to start it.
#include <circle/sched/task.h>
-
class CTask
-
CTask::CTask(unsigned nStackSize = TASK_STACK_SIZE, boolean bCreateSuspended = FALSE)
Creates a task.
nStackSize
is the stack size for this task. By default a new task is immediately ready to run and itsRun()
method can be called. If you have to do more initialization, before the task can run, setbCreateSuspended
toTRUE
. The task has to be started explicitly by callingStart()
on it then.
-
virtual void CTask::Run(void)
Override this method to define the entry point for your own task. The task is automatically terminated, when
Run()
returns.
-
void CTask::Start(void)
Starts a task, that was created with
bCreateSuspended = TRUE
or restarts it afterSuspend()
.
-
boolean CTask::IsSuspended(void) const
Returns
TRUE
, if the task is currently suspended from running.
-
void CTask::Terminate(void)
Terminates the execution of the task. This method can only be called by the task itself. The task terminates on return from
Run()
too.
-
void CTask::WaitForTermination(void)
Waits for the termination of the task. This method can only be called by an other task.
-
const char *CTask::GetName(void) const
Returns a pointer to 0-terminated name string of this task. The default name of a task is constructed from the address of its task object (e.g.
"@84abc0"
). The main application task has the name"main"
.
CMutex
Provides a method to provide mutual exclusion (critical sections) across tasks.
#include <circle/sched/mutex.h>
-
class CMutex
CSemaphore
Implements the well-known semaphore synchronization concept, which was initially defined by Dijkstra. The class maintains a non-negative counter, which is decremented with the Down()
operation. When this is not possible, because the counter is already zero, the calling task waits, until the counter is incremented again. This is possible with the Up()
operation. Semaphores can be used to control the access to a limited number of resources.
#include <circle/sched/semaphore.h>
-
class CSemaphore
-
CSemaphore::CSemaphore(unsigned nInitialCount = 1)
Creates a semaphore.
nInitialCount
is the initial count of the semaphore.
-
unsigned CSemaphore::GetState(void) const
Returns the current count of the semaphore.
-
void CSemaphore::Down(void)
Decrements the semaphore count. Blocks the calling task, if the count is already zero.
-
void CSemaphore::Up(void)
Increments the semaphore count. Wakes another waiting task, if the count was zero. Can be called from interrupt context.
-
boolean CSemaphore::TryDown(void)
Tries to decrement the semaphore count. Returns
TRUE
on success orFALSE
, if the count is zero.
CSynchronizationEvent
Provides a method to synchronize the execution of tasks with an event. The event can be set or cleared. If a task is waiting for the event, it is blocked, when the event is cleared (unset) and will continue execution, when the event is set again. Multiple tasks can wait for the event at the same time.
#include <circle/sched/synchronizationevent.h>
-
class CSynchronizationEvent
-
CSynchronizationEvent::CSynchronizationEvent(boolean bState = FALSE)
Creates the synchronization event.
bState
is the initial state of the event (default cleared).
-
boolean CSynchronizationEvent::GetState(void)
Returns the current state for the synchronization event.
-
void CSynchronizationEvent::Clear(void)
Clears the synchronization event.
-
void CSynchronizationEvent::Set(void)
Sets the synchronization event. Wakes all tasks currently waiting for the event. Can be called from interrupt context.
-
void CSynchronizationEvent::Wait(void)
Blocks the calling task, if the synchronization event is cleared. The task will wake up, when the event is set later. Multiple tasks can wait for the event to be set.
-
boolean CSynchronizationEvent::WaitWithTimeout(unsigned nMicroSeconds)
Blocks the calling task for
nMicroSeconds
microseconds, if the synchronization event is cleared. The task will wake up, when the event is set later. Multiple tasks can wait for the event to be set. This method returnsTRUE
, ifnMicroSeconds
microseconds have elapsed, before the event has been set. To determine, what caused the method to return, useGetState()
to see, if the event has been set. It is possible to have timed out and the event is set anyway.
USB
The USB (Universal Serial Bus) subsystem provides services and device drivers, which support the access to USB 2.0 and USB 3.0 (on the Raspberry Pi 4 only) devices. Essentially, this concerns drivers for the DWHCI OTG USB controller of the Raspberry Pi 1-3 and Zero (host mode only) and the xHCI USB controller(s) of the Raspberry Pi 4 (400 and Compute Module 4 too), USB device class drivers, some vendor specific USB device drivers and support classes for all these drivers.
Most of the operations in this subsystem are hidden from applications behind device driver interfaces, which will be described in the Devices section. An application, which uses the USB, has especially to deal with the initialization of the USB support at system startup and optionally with detecting newly attached USB devices, while the system is running (USB plug-and-play). This section is limited to these topics.
Please read the file doc/usb-plug-and-play.txt for general information about the (optional) USB plug-and-play support in Circle.
CUSBHCIDevice
#include <circle/usb/usbhcidevice.h>
-
class CUSBHCIDevice : public CUSBHostController
This class is the base of the USB support in a Circle application. To use USB, you should create a member of this class in the
CKernel
class of your application.
Note
Actually there is not really a class CUSBHCIDevice
available in Circle. Instead, two classes CDWHCIDevice
and CXHCIDevice
(both derived from CUSBHostController
) exist for the respective USB host controllers of the target Raspberry Pi model, and CUSBHCIDevice
is only an alias for these class names, defined as macro. To ensure, that an application can be built for each Raspberry Pi model, you should use the name CUSBHCIDevice
only.
Some methods available via CUSBHCIDevice
are defined in its base class CUSBHostController and can be called using a pointer to a CUSBHostController
object too.
-
CUSBHCIDevice::CUSBHCIDevice(CInterruptSystem *pInterruptSystem, CTimer *pTimer, boolean bPlugAndPlay = FALSE)
Creates an instance of this class.
pInterruptSystem
is a pointer to the interrupt system object andpTimer
a pointer to the system timer object.bPlugAndPlay
must be set toTRUE
to enable the USB plug-and-play support. This is optional and requires further support by the application.
-
boolean CUSBHCIDevice::Initialize(boolean bScanDevices = TRUE)
Initializes the USB subsystem. Normally this includes a bus scan and the initialization of all attached USB devices, which takes some time. To speed-up the USB initialization,
bScanDevices
can be set toFALSE
, if USB plug-and-play was enabled in the constructor of this class (bPlugAndPlay = TRUE
). The device initialization will be deferred to a later call ofUpdatePlugAndPlay()
then.
-
void CUSBHCIDevice::ReScanDevices(void)
This method can be invoked to re-scan the USB for newly attached devices, in case USB plug-and-play support has not been enabled, when calling the constructor of this class (
bPlugAndPlay = FALSE
).
CUSBHostController
#include <circle/usb/usbhostcontroller.h>
-
class CUSBHostController
This is the base class of
CDWHCIDevice
andCXHCIDevice
(akaCUSBHCIDevice
). The following methods can be called for an instance of these classes too.
-
static boolean CUSBHostController::IsPlugAndPlay(void)
Returns
TRUE
, if USB plug-and-play is supported by the USB subsystem.
-
boolean CUSBHostController::UpdatePlugAndPlay(void)
If USB plug-and-play is enabled, this method must be called continuously from
TASK_LEVEL
, so that the internal USB device tree can be updated, if new devices have been attached or devices have been removed from the USB. ReturnsTRUE
, if the USB device tree might have been changed. The application should test for the existence of devices, which it supports, by invokingCDeviceNameService::GetDevice()
then.UpdatePlugAndPlay()
always returnsTRUE
on its first call.
-
static boolean CUSBHostController::IsActive(void)
Returns
TRUE
, if the USB subsystem is available.
-
static CUSBHostController *CUSBHostController::Get(void)
Returns a pointer to the only instance of
CUSBHostController
(akaCUSBHCIDevice
) in the system.
Filesystems
Circle provides two different implementations for FAT filesystem support:
A native filesystem subsystem with FAT16 and FAT32 support using C++ classes, which has several limitations: short filenames (8.3) only, access to the root directory only, sequential file access only, subset of common file operations only, relatively slow
A port of FatFs - Generic FAT Filesystem Module (by ChaN), written in C, but with full FAT filesystem support and much faster
CFATFileSystem
#include <circle/fs/fat/fatfs.h>
-
class CFATFileSystem
This class provides the API of the native FAT filesystem support in Circle, which has several limitations (see above). If you want to use this variant, you should instantiate this class as a member of the class
CKernel
.
-
int CFATFileSystem::Mount(CDevice *pPartition)
Mounts the block device
pPartition
as FAT filesystem. Returns non-zero on success. A pointer to the block device can be requested usingCDeviceNameService::GetDevice()
. This method is usually invoked with the partition name"emmc1-1"
(first partition of the SD card) or"umsd1-1"
(first partition of an USB mass-storage device, e.g. USB flash drive) for this purpose.
-
void CFATFileSystem::UnMount(void)
Un-mounts the filesystem.
-
void CFATFileSystem::Synchronize(void)
Flushes the buffer cache, without un-mounting the filesystem.
-
unsigned CFATFileSystem::RootFindFirst(TDirentry *pEntry, TFindCurrentEntry *pCurrentEntry)
Finds the first file entry in the root directory and returns non-zero, if it was found.
pEntry
is a pointer to a buffer, which receives the information about the found file.pCurrentEntry
points to the current entry variable, which must be maintained, until the directory scan has been completed.TDirentry
is defined as follows:
#define FS_TITLE_LEN 12 // length of a file name (may include a dot)
struct TDirentry
{
char chTitle[FS_TITLE_LEN+1]; // 0-terminated
unsigned nSize; // number of bytes
unsigned nAttributes;
#define FS_ATTRIB_NONE 0x00 // no attribute set
#define FS_ATTRIB_SYSTEM 0x01 // HIDDEN attribute set
#define FS_ATTRIB_EXECUTABLE 0x02 // file is executable (always set for FAT)
};
-
unsigned CFATFileSystem::RootFindNext(TDirentry *pEntry, TFindCurrentEntry *pCurrentEntry)
Finds the next file entry in the root directory and returns non-zero, if it was found, or zero, if there are no more entries.
pEntry
is a pointer to a buffer, which receives the information about the found file.pCurrentEntry
points to the current entry variable, which must be maintained, until the directory scan has been completed. SeeRootFindFirst()
for the definition of TDirentry.
-
unsigned CFATFileSystem::FileOpen(const char *pTitle)
Opens the file with the filename
pTitle
(8.3 name without path, may include a dot) for read. Returns the file handle or zero on failure.
-
unsigned CFATFileSystem::FileCreate(const char *pTitle)
Creates a new file with the filename
pTitle
(8.3 name without path, may include a dot) for write. Returns the file handle or zero on failure (e.g. read-only file with this name exists).
Warning
This method truncates the file, if it already exists with the filename pTitle
.
-
unsigned CFATFileSystem::FileClose(unsigned hFile)
Closes the file with the file handle
hFile
. This handle has been returned by a previous call toFileOpen()
orFileCreate()
. Returns non-zero on success.
-
unsigned CFATFileSystem::FileRead(unsigned hFile, void *pBuffer, unsigned nCount)
Reads sequentially up to
nCount
bytes from the file with file handlehFile
intopBuffer
. Returns the number of bytes read, zero when the end of file has been reached, or FS_ERROR on general failure (e.g. invalid parameter).
-
unsigned CFATFileSystem::FileWrite(unsigned hFile, const void *pBuffer, unsigned nCount)
Writes sequentially
nCount
bytes frompBuffer
to the file with file handlehFile
. Returns the number of bytes written, or FS_ERROR on general failure (e.g. invalid parameter).
-
int CFATFileSystem::FileDelete(const char *pTitle)
Deletes the file with the name
pTitle
from the root directory. Returns a positive value on success, zero, if the file was not found, or a negative value, if the file has the read-only attribute.
FatFs library
The FatFs - Generic FAT Filesystem Module (by ChaN) has been ported to Circle, to provide a full function support for the FAT filesystem. The related files can be found in the subdirectory addon/fatfs. The associated sample program demonstrates some basic features of FatFs. Please see the subsection “Application Interface” on this website for a description of the different functions of this library.
The Circle port of FatFs supports the following volume ID strings for logical drives:
ID |
Drive |
Partition |
Device |
---|---|---|---|
SD: |
0: |
first FAT partition |
SD card |
USB: |
1: |
first FAT partition |
first USB mass-storage device |
USB2: |
2: |
first FAT partition |
second USB mass-storage device |
USB3: |
3: |
first FAT partition |
third USB mass-storage device |
Important
FatFs may support the exFAT filesystems too. This support has been disabled in Circle for legal reasons. You have to read the subsection “exFAT Filesystem” on the page FatFs Module Application Note first, if you want to use exFAT support! This may require a license fee.
TCP/IP networking
This section describes the TCP/IP networking support in Circle. This covers initialization and configuration, the socket API, the available upper layer protocol clients and servers and a few utility classes. The TCP/IP networking support requires the scheduler in the system (see Multitasking).
The following sample programs demonstrate TCP/IP networking features:
Sample |
Description |
---|---|
18-ntptime |
Setting the system time from a NTP server |
20-tcpsimple |
TCP echo server |
21-webserver |
Simple HTTP webserver |
31-webclient |
Simple HTTP client (only for reference) |
33-syslog |
Send log messages to an UDP syslog server |
35-mqttclient |
MQTT client |
38-bootloader |
HTTP- and TFTP-based bootloader |
CNetSubSystem
#include <circle/net/netsubsystem.h>
-
class CNetSubSystem
This class represents the TCP/IP support in Circle. There can be only one instance of this class.
-
CNetSubSystem::CNetSubSystem(const u8 *pIPAddress = 0, const u8 *pNetMask = 0, const u8 *pDefaultGateway = 0, const u8 *pDNSServer = 0, const char *pHostname = "raspberrypi", TNetDeviceType DeviceType = NetDeviceTypeEthernet)
Creates the
CNetSubSystem
instance. The parameterspIPAddress
,pNetMask
,pDefaultGateway
andpDNSServer
point to 4-byte arrays, which define the network configuration (e.g. IP address {192, 168, 0, 42}). Set all these pointers to 0 to enable the dynamic network configuration using DHCP instead.pHostname
specifies the host name, which is sent to the DHCP server (0 to disable).DeviceType
can beNetDeviceTypeEthernet
(default) orNetDeviceTypeWLAN
.
Note
Setting DeviceType
to NetDeviceTypeWLAN
is not enough to access a WLAN. Instead you have to instantiate and initialize the classes CBcm4343Device
(WLAN hardware driver), CNetSubSystem
and CWPASupplicant
(support task for secure WLAN access) in this order. Please see the subsection WLAN support and the WLAN sample for details!
-
boolean CNetSubSystem::Initialize(boolean bWaitForActivate = TRUE)
Initializes the network subsystem. Usually this method returns after the network configuration has been assigned, if DHCP is enabled. This requires that the DHCP server can be reached and takes some time. If you want to speedup network initialization, you can set the parameter
bWaitForActivate
toFALSE
. Then this method will return immediately after initialization, but you have to test on your own, if the network is available using the methodIsRunning()
, before accessing the network.
-
boolean CNetSubSystem::IsRunning(void) const
Returns
TRUE
, when is TCP/IP network is available and configured. If DHCP is enabled, this means that an IP address is already bound.
-
CNetConfig *CNetSubSystem::GetConfig(void)
Returns a pointer to the network configuration, which is saved in an instance of the class
CNetConfig
. This is usually used to inform the user about the dynamically assigned configuration. You should not try to manipulate the configuration using this pointer.
-
static CNetSubSystem *CNetSubSystem::Get(void)
Returns a pointer to the instance of
CNetSubSystem
.
CNetConfig
#include <circle/net/netconfig.h>
-
class CNetConfig
An instance of this class holds the configuration of the TCP/IP networking subsystem. A pointer to this instance can be requested using
CNetSubSystem::GetConfig()
. The following methods can be used to get the different configuration items.
-
boolean CNetConfig::IsDHCPUsed(void) const
Returns
TRUE
if the network is configured dynamically using DHCP.
-
const CIPAddress *CNetConfig::GetIPAddress(void) const
Returns our own IP address.
-
const u8 *CNetConfig::GetNetMask(void) const
Returns the net mask of the local network, we are connected to.
-
const CIPAddress *CNetConfig::GetDefaultGateway(void) const
Returns the IP address of the default gateway into the Internet.
-
const CIPAddress *CNetConfig::GetDNSServer(void) const
Returns the IP address of the Domain Name Service server.
-
const CIPAddress *CNetConfig::GetBroadcastAddress(void) const
Returns the (directed) broadcast address, which is valid in the local network, we are connected to.
CSocket
#include <circle/net/socket.h>
#include <circle/net/in.h> // for IPPROTO_*, MSG_DONTWAIT
#include <circle/netdevice.h> // for FRAME_BUFFER_SIZE
-
class CSocket : public CNetSocket
This class forms the API for TCP/IP network access in Circle.
Note
Port numbers at the Circle socket API are in host byte order. This means you do not need to swap the byte order to network order, when you specify a little endian number to an API function.
Operations can be blocking or non-blocking. Blocking operations wait for the completion, before the function returns. Non-blocking operations return immediately, which means that you have to ensure on your own, that the system is not congested, e.g. if sending much data.
-
CSocket::CSocket(CNetSubSystem *pNetSubSystem, int nProtocol)
Creates a
CSocket
object, which represents one TCP/IP connection in Circle.pNetSubSystem
is a pointer to the network subsystem.nProtocol
can beIPPROTO_TCP
orIPPROTO_UDP
.
-
int CSocket::Bind(u16 usOwnPort)
Binds the port number
usOwnPort
to this socket. Returns 0 on success or < 0 on error.
-
int CSocket::Connect(CIPAddress &rForeignIP, u16 usForeignPort)
Connects to a foreign host/port (TCP) or setup a foreign host/port address (UDP).
rForeignIP
is the IP address of the host to be connected.usForeignPort
is the number of the port to be connected. Returns 0 on success or < 0 on error.
-
int CSocket::Listen(unsigned nBackLog = 4)
Listens for incoming connections (TCP only). You must call
Bind()
before.nBackLog
is the maximum number of simultaneous connections, which may be accepted in a row beforeAccept()
is called (up to 32). Returns 0 on success or < 0 on error.
-
CSocket *CSocket::Accept(CIPAddress *pForeignIP, u16 *pForeignPort)
Accepts an incoming connection (TCP only). You must call
Listen()
before.pForeignIP
points to aCIPAddress
object, which receives the IP address of the remote host. The remote port number will be returned in*pForeignPort
. Returns a newly created socket to be used to communicate with the remote host, or 0 on error.
-
int CSocket::Send(const void *pBuffer, unsigned nLength, int nFlags)
Sends a message to a remote host.
pBuffer
is a pointer to the message andnLength
is its length in bytes.nFlags
can beMSG_DONTWAIT
(non-blocking operation) or 0 (blocking operation). Returns the length of the sent message or < 0 on error.
-
int CSocket::Receive(void *pBuffer, unsigned nLength, int nFlags)
Receives a message from a remote host.
pBuffer
is a pointer to the message buffer andnLength
is its size in bytes.nLength
should be at leastFRAME_BUFFER_SIZE
, otherwise data may get lost.nFlags
can beMSG_DONTWAIT
(non-blocking operation) or 0 (blocking operation). Returns the length of received message, which is 0 withMSG_DONTWAIT
if no message is available, or < 0 on error.
-
int CSocket::SendTo(const void *pBuffer, unsigned nLength, int nFlags, CIPAddress &rForeignIP, u16 nForeignPort)
Sends a message to a specific remote host.
pBuffer
is a pointer to the message andnLength
is its length in bytes.nFlags
can beMSG_DONTWAIT
(non-blocking operation) or 0 (blocking operation).rForeignIP
is the IP address of the host to be sent to (ignored on TCP socket).nForeignPort
is the number of the port to be sent to (ignored on TCP socket). Returns the length of the sent message or < 0 on error.
-
int CSocket::ReceiveFrom(void *pBuffer, unsigned nLength, int nFlags, CIPAddress *pForeignIP, u16 *pForeignPort)
Receives a message from a remote host, returns host/port of remote host.
pBuffer
is a pointer to the message buffer andnLength
is its size in bytes.nLength
should be at leastFRAME_BUFFER_SIZE
, otherwise data may get lost.nFlags
can beMSG_DONTWAIT
(non-blocking operation) or 0 (blocking operation).pForeignIP
is a pointer to aCIPAddress
object, which receives the IP address of the host, which has sent the message. The number of the port from which the message has been sent will be returned in*pForeignPort
. Returns the length of the received message, which is 0 withMSG_DONTWAIT
if no message is available, or < 0 on error.
-
int CSocket::SetOptionBroadcast(boolean bAllowed)
bAllowed
specifies weather sending and receiving broadcast messages is allowed on this socket (defaultFALSE
). Call this withbAllowed = TRUE
afterBind()
orConnect()
to be able to send and/or receive broadcast messages (ignored on TCP socket). Returns 0 on success or < 0 on error.
Clients
CDNSClient
#include <circle/net/dnsclient.h>
-
class CDNSClient
This class supports the resolve of an Internet domain host name to an IP address.
-
CDNSClient::CDNSClient(CNetSubSystem *pNetSubSystem)
Creates a
CDNSClient
object.pNetSubSystem
is a pointer to the network subsystem.
-
boolean CDNSClient::Resolve(const char *pHostname, CIPAddress *pIPAddress)
Resolves the host name
pHostname
to an IP address, returned in*pIPAddress
.pHostname
can be a dotted IP address string (e.g. “192.168.0.42”) too, which will be converted. ReturnsTRUE
on success.
CHTTPClient
#include <circle/net/httpclient.h>
#include <circle/net/http.h> // for THTTPStatus
-
class CHTTPClient
This class can be used to generate requests to a HTTP server.
Note
In the Internet of today there are only a few webservers any more, which provide plain HTTP access. For HTTPS (HTTP over TLS) access with Circle you can use the circle-stdlib project, which includes Circle as a submodule.
-
CHTTPClient::CHTTPClient(CNetSubSystem *pNetSubSystem, CIPAddress &rServerIP, u16 usServerPort = HTTP_PORT, const char *pServerName = 0)
Creates a
CHTTPClient
object.pNetSubSystem
is a pointer to the network subsystem.rServerIP
is the IP address of the server andusServerPort
the server port to connect.pServerName
is the host name of the server, which is required for the access to virtual servers (multiple websites with different host names, hosted on the same server).
-
THTTPStatus CHTTPClient::Get(const char *pPath, u8 *pBuffer, unsigned *pLength)
Sends a GET request to the server.
pPath
is the absolute path of the requested document, optionally with appended parameters:/path/filename.ext[?name=value[&name=value...]]
The received content will be returned in
pBuffer
.*pLength
is the buffer size in bytes on input and the received content length on output. Returns the HTTP status (HTTPOK
on success).
-
THTTPStatus CHTTPClient::Post(const char *pPath, u8 *pBuffer, unsigned *pLength, const char *pFormData)
Sends a POST request to the server.
pPath
is the absolute path of the requested document, optionally with appended parameters:/path/filename.ext[?name=value[&name=value...]]
The received content will be returned in
pBuffer
.*pLength
is the buffer size in bytes on input and the received content length on output.pFormData
are the posted parameters in this format:name=value[&name=value...]
Returns the HTTP status (
HTTPOK
on success).
CNTPClient
#include <circle/net/ntpclient.h>
-
class CNTPClient
This class can be used to request the current time from a Network Time Protocol server.
-
CNTPClient::CNTPClient(CNetSubSystem *pNetSubSystem)
Creates a
CNTPClient
object.pNetSubSystem
is a pointer to the network subsystem.
-
unsigned CNTPClient::GetTime(CIPAddress &rServerIP)
Requests the current time from a NTP server.
rServerIP
is the IP address from the NTP server, which can be resolved using the classCDNSClient
. Returns the current time in seconds since 1970-01-01 00:00:00 UTC, or 0 on error.
CNTPDaemon
#include <circle/net/ntpdaemon.h>
-
class CNTPDaemon : public CTask
This class is a background task, which continuously (all 15 minutes) updates the Circle system time from a NTP server. It uses the class
CNTPClient
.
-
CNTPDaemon::CNTPDaemon(const char *pNTPServer, CNetSubSystem *pNetSubSystem)
Creates the
CNTPDaemon
task.pNTPServer
is the host name of the NTP server (e.g. “pool.ntp.org”).pNetSubSystem
is a pointer to the network subsystem. This object must be created using thenew
operator.
CMQTTClient
#include <circle/net/mqttclient.h>
-
class CMQTTClient : public CTask
This class is a client for the MQTT protocol, according to the MQTT v3.1.1 specification. It is implemented as a task. To use this class, you have to derive a user defined class from
CMQTTClient
and override its virtual methods. The task must be created with thenew
operator.
Warning
This implementation does not support multi-byte-characters in strings.
-
CMQTTClient::CMQTTClient(CNetSubSystem *pNetSubSystem, size_t nMaxPacketSize = 1024, size_t nMaxPacketsQueued = 4, size_t nMaxTopicSize = 256)
Creates a
CMQTTClient
task.pNetSubSystem
is a pointer to the network subsystem.nMaxPacketSize
is the maximum allowed size of a MQTT packet sent or received (topic size + payload size + a few bytes protocol overhead).nMaxPacketsQueued
is the maximum number of MQTT packets queue-able on receive. If processing a received packet takes longer, further packets have to be queued.nMaxTopicSize
is the maximum allowed size of a received topic string.
-
boolean CMQTTClient::IsConnected(void) const
Returns
TRUE
if an active connection to the MQTT broker exists.
-
void CMQTTClient::Connect(const char *pHost, u16 usPort = MQTT_PORT, const char *pClientIdentifier = 0, const char *pUsername = 0, const char *pPassword = 0, u16 usKeepAliveSeconds = 60, boolean bCleanSession = TRUE, const char *pWillTopic = 0, u8 uchWillQoS = 0, boolean bWillRetain = FALSE, const u8 *pWillPayload = 0, size_t nWillPayloadLength = 0)
Establishes a connection to the MQTT broker
pHost
(host name or IP address as a dotted string).usPort
is the port number of the MQTT broker service (default 1883).pClientIdentifier
is the identifier string of this client (if 0 set internally toraspiNNNNNNNNNNNNNNNN
, N = hex digits of the serial number).pUsername
is the user name for authorization (0 if not required).pPassword
is the password for authorization (0 if not required).usKeepAliveSeconds
is the duration of the keep alive period in seconds (default 60).bCleanSession
specifies, if this should be a clean MQTT session. (default TRUE).pWillTopic
is the topic string for the last will message (no last will message if 0).uchWillQoS
is the QoS setting for last will message (default unused).bWillRetain
is the retain parameter for last will message (default unused).pWillPayload
is a pointer to the last will message payload (default unused).nWillPayloadLength
is the length of the last will message payload (default unused).
-
void CMQTTClient::Disconnect(boolean bForce = FALSE)
Closes the connection to a MQTT broker.
bForce
forces a TCP disconnect only and does not send a MQTT DISCONNECT packet.
-
void CMQTTClient::Subscribe(const char *pTopic, u8 uchQoS = MQTT_QOS2)
Subscribes to the MQTT topic
pTopic
(may include wildchars).uchQoS
is the maximum QoS value for receiving messages with this topic (default QoS 2).
-
void CMQTTClient::Unsubscribe(const char *pTopic)
Unsubscribes from the MQTT topic
pTopic
.
-
void CMQTTClient::Publish(const char *pTopic, const u8 *pPayload = 0, size_t nPayloadLength = 0, u8 uchQoS = MQTT_QOS1, boolean bRetain = FALSE)
Publishes the MQTT topic
pTopic
.pPayload
is a pointer to the message payload (default unused).nPayloadLength
is the length of the message payload (default 0).uchQoS
is the QoS value for sending the PUBLISH message (default QoS 1).bRetain
is the retain parameter for the message (default FALSE).
-
virtual void CMQTTClient::OnConnect(boolean bSessionPresent)
This is a callback entered when the connection to the MQTT broker has been established.
bSessionPresent
specifies, if a session was already present on the server for this client.
-
virtual void CMQTTClient::OnDisconnect(TMQTTDisconnectReason Reason)
This is a callback entered when the connection to the MQTT broker has been closed.
Reason
is the reason for closing the connection, which can be:
enum TMQTTDisconnectReason
{
MQTTDisconnectFromApplication = 0,
// CONNECT errors
MQTTDisconnectUnacceptableProtocolVersion = 1,
MQTTDisconnectIdentifierRejected = 2,
MQTTDisconnectServerUnavailable = 3,
MQTTDisconnectBadUsernameOrPassword = 4,
MQTTDisconnectNotAuthorized = 5,
// additional errors
MQTTDisconnectDNSError,
MQTTDisconnectConnectFailed,
MQTTDisconnectFromPeer,
MQTTDisconnectInvalidPacket,
MQTTDisconnectPacketIdentifier,
MQTTDisconnectSubscribeError,
MQTTDisconnectSendFailed,
MQTTDisconnectPingFailed,
MQTTDisconnectNotSupported,
MQTTDisconnectInsufficientResources,
MQTTDisconnectUnknown
};
-
virtual void CMQTTClient::OnMessage(const char *pTopic, const u8 *pPayload, size_t nPayloadLength, boolean bRetain)
This is a callback entered when a PUBLISH message has been received for a subscribed topic.
pTopic
is the topic of the received message.pPayload
is a pointer to the payload of the received message.nPayloadLength
is the length of the payload of the received message.bRetain
is the retain parameter of the received message.
-
virtual void CMQTTClient::OnLoop(void)
This is a callback regularly entered from the MQTT client task.
CSysLogDaemon
#include <circle/net/syslogdaemon.h>
-
class CSysLogDaemon : public CTask
This class is a background task, which sends the messages from the System log to a RFC5424/RFC5426 syslog server via UDP.
-
CSysLogDaemon::CSysLogDaemon(CNetSubSystem *pNetSubSystem, const CIPAddress &rServerIP, u16 usServerPort = SYSLOG_PORT)
Creates the
CSysLogDaemon
task.pNetSubSystem
is a pointer to the network subsystem.rServerIP
is the IP address of the syslog server.usServerPort
is the port number of the syslog server (default 514). This object must be created using thenew
operator.
Servers
CHTTPDaemon
#include <circle/net/httpdaemon.h>
#include <circle/net/http.h> // for THTTPStatus
-
class CHTTPDaemon : public CTask
This class implements a simple HTTP server as a task. You have to derive a user class from it, override the virtual methods and create it using the
new
operator to start it.
Note
This class uses a listener/worker model. The initially created task listens for incoming requests (listener) and spawns a child task (worker), which processes the request and terminates afterwards.
-
CHTTPDaemon::CHTTPDaemon(CNetSubSystem *pNetSubSystem, CSocket *pSocket = 0, unsigned nMaxContentSize = 0, u16 nPort = HTTP_PORT, unsigned nMaxMultipartSize = 0)
Creates the
CHTTPDaemon
task.pNetSubSystem
is a pointer to the network subsystem.pSocket
is 0 for first created instance (listener).nMaxContentSize
is the buffer size for the content of the created worker tasks. Set this parameter to the maximum length in bytes of a webpage, which is generated by your server.nPort
is the port number to listen on (default 80).nMaxMultipartSize
is the buffer size for received multipart form data. If your server receives requests, which include multipart form data, this parameter must be set to the maximum length of this data, which you want to process.
-
virtual CHTTPDaemon *CHTTPDaemon::CreateWorker(CNetSubSystem *pNetSubSystem, CSocket *pSocket) = 0
Creates a worker instance of your derived webserver class.
pNetSubSystem
is a pointer to the network subsystem.pSocket
is the socket that manages the incoming connection. Both parameters have to be handed over to the constructor of your derived webserver class, to be passed toCHTTPDaemon::CHTTPDaemon
. See this example:
class CMyWebServer : public CHTTPDaemon
{
public:
CMyWebServer (CNetSubSystem *pNetSubSystem,
CActLED *pActLED, // some user data
CSocket *pSocket = 0); // 0 for first instance
CHTTPDaemon *CreateWorker (CNetSubSystem *pNetSubSystem,
CSocket *pSocket);
...
};
#define MAX_CONTENT_SIZE 4000 // maximum content size of your pages
CMyWebServer::CMyWebServer (CNetSubSystem *pNetSubSystem,
CActLED *pActLED,
CSocket *pSocket)
: CHTTPDaemon (pNetSubSystem, pSocket, MAX_CONTENT_SIZE),
m_pActLED (pActLED)
{
}
CHTTPDaemon *CMyWebServer::CreateWorker (CNetSubSystem *pNetSubSystem,
CSocket *pSocket)
{
return new CMyWebServer (pNetSubSystem, m_pActLED, pSocket);
}
-
virtual THTTPStatus CHTTPDaemon::GetContent(const char *pPath, const char *pParams, const char *pFormData, u8 *pBuffer, unsigned *pLength, const char **ppContentType) = 0
Define this method to provide your own content.
pPath
is the path of the file to be sent (e.g. “/index.html”, can be “/” too).pParams
are the GET parameters (”” for none).pFormData
contains the parameters from the form data from POST (”” for none). Copy your content topBuffer
.*pLength
is the buffer size in bytes on input and the content length on output.*ppContentType
must be set to the MIME type, if it is not “text/html”. This method has to return the HTTP status (HTTPOK
on success).
-
virtual void CHTTPDaemon::WriteAccessLog(const CIPAddress &rRemoteIP, THTTPRequestMethod RequestMethod, const char *pRequestURI, THTTPStatus Status, unsigned nContentLength)
Overwrite this method to implement your own access logging.
rRemoteIP
is the IP address of the client.RequestMethod
is the method of the request andpRequestURI
its URI.Status
andnContentLength
specify the returned HTTP status number and the length of the sent content. The default implementation of this method writes a message to the System log.
-
boolean CHTTPDaemon::GetMultipartFormPart(const char **ppHeader, const u8 **ppData, unsigned *pLength)
This method can be called from
GetContent()
and returns the next part of multipart form data (TRUE
if available). This data is not available after returning fromGetContent()
any more.*ppHeader
returns a pointer to the part header.*ppData
returns a pointer to part data.*pLength
returns the part data length.
CTFTPDaemon
#include <circle/net/tftpdaemon.h>
-
class CTFTPDaemon : public CTask
This class provides a server task for the TFTP protocol. You have to implement the pure virtual methods in a derived class, start the task with the
new
operator and will be able to receive and handle TFTP requests. This server can handle only one connection at a time, and works in binary mode only. The TFTP fileserver sample demonstrates the usage of this class.
-
CTFTPDaemon::CTFTPDaemon(CNetSubSystem *pNetSubSystem)
Creates the
CTFTPDaemon
task.pNetSubSystem
is a pointer to the network subsystem.
-
virtual boolean CTFTPDaemon::FileOpen(const char *pFileName) = 0
Virtual method entered to open a file for read to be sent via TFTP.
pFileName
is the file name sent by the client. ReturnsTRUE
on success.
-
virtual boolean CTFTPDaemon::FileCreate(const char *pFileName) = 0
Virtual method entered to create a file for write to be received via TFTP.
pFileName
is the file name sent by the client. ReturnsTRUE
on success.
-
virtual boolean CTFTPDaemon::FileClose(void) = 0
Virtual method entered to close the currently open file. Returns
TRUE
on success.
-
virtual int CTFTPDaemon::FileRead(void *pBuffer, unsigned nCount) = 0
Virtual method entered to read
nCount
bytes from the currently open file intopBuffer
. Returns the number of bytes read, or < 0 on error.
-
virtual int CTFTPDaemon::FileWrite(const void *pBuffer, unsigned nCount) = 0
Virtual method entered to write
nCount
bytes frompBuffer
into the currently open file. Returns the number of bytes written, or < 0 on error.
Utilities
CIPAddress
#include <circle/net/ipaddress.h>
-
IP_ADDRESS_SIZE
The size of an IP (v4) address (4 bytes).
-
class CIPAddress
This class encapsulates an IP (v4) address.
-
CIPAddress::CIPAddress(void)
-
CIPAddress::CIPAddress(u32 nAddress)
-
CIPAddress::CIPAddress(const u8 *pAddress)
-
CIPAddress::CIPAddress(const CIPAddress &rAddress)
Creates an
CIPAddress
object. Initialize it from different address formats.
-
boolean CIPAddress::operator==(const CIPAddress &rAddress2) const
-
boolean CIPAddress::operator!=(const CIPAddress &rAddress2) const
-
boolean CIPAddress::operator==(const u8 *pAddress2) const
-
boolean CIPAddress::operator!=(const u8 *pAddress2) const
-
boolean CIPAddress::operator==(u32 nAddress2) const
-
boolean CIPAddress::operator!=(u32 nAddress2) const
Compares this IP address with a second IP address in different formats.
-
CIPAddress &CIPAddress::operator=(u32 nAddress)
Assign a new IP address
nAddress
.
-
void CIPAddress::Set(u32 nAddress)
-
void CIPAddress::Set(const u8 *pAddress)
-
void CIPAddress::Set(const CIPAddress &rAddress)
Sets the IP address in different formats.
-
void CIPAddress::SetBroadcast(void)
Sets the IP address to the broadcast address (255.255.255.255).
-
CIPAddress::operator u32(void) const
Returns the IP address as
u32
value.
-
const u8 *CIPAddress::Get(void) const
Returns a pointer to the IP address as an array with 4 bytes.
-
void CIPAddress::CopyTo(u8 *pBuffer) const
Copy the IP address to a buffer (4 bytes).
-
boolean CIPAddress::IsNull(void) const
Returns
TRUE
, if the IP address components are all zero (0.0.0.0).
-
boolean CIPAddress::IsBroadcast(void) const
Returns
TRUE
if the IP address is the broadcast address (255.255.255.255).
-
unsigned CIPAddress::GetSize(void) const
Returns the size of an IP (v4) address (4).
-
void CIPAddress::Format(CString *pString) const
Sets
*pString
to the dotted string representation of the IP address.
-
boolean CIPAddress::OnSameNetwork(const CIPAddress &rAddress2, const u8 *pNetMask) const
Returns
TRUE
, if this IP address is on the same network asrAddress2
withpNetMask
applied.
CMACAddress
#include <circle/macaddress.h>
Note
This class is belongs to the Circle base library, because it is needed there to implement non-USB network device drivers.
-
MAC_ADDRESS_SIZE
The size of an (Ethernet) MAC address (6 bytes).
-
class CMACAddress
This class encapsulates an (Ethernet) MAC address.
-
CMACAddress::CMACAddress(void)
Creates an
CMACAddress
object. The address is initialized as “invalid” and must be set, before it can be read.
-
CMACAddress::CMACAddress(const u8 *pAddress)
Creates an
CMACAddress
object. Set it frompAddress
, which points to an array with 6 bytes.
-
boolean CMACAddress::operator==(const CMACAddress &rAddress2) const
-
boolean CMACAddress::operator!=(const CMACAddress &rAddress2) const
Compares this MAC address with a second MAC address.
-
void CMACAddress::Set(const u8 *pAddress)
Sets the MAC address to
pAddress
, which points to an array with 6 bytes.
-
void CMACAddress::SetBroadcast(void)
Sets the MAC address to the (Ethernet) broadcast address (FF:FF:FF:FF:FF:FF).
-
const u8 *CMACAddress::Get(void) const
Returns a pointer to the MAC address as an array with 6 bytes.
-
void CMACAddress::CopyTo(u8 *pBuffer) const
Copy the MAC address to a buffer (6 bytes).
-
boolean CMACAddress::IsBroadcast(void) const
Returns
TRUE
if the MAC address is the (Ethernet) broadcast address (FF:FF:FF:FF:FF:FF).
-
unsigned CMACAddress::GetSize(void) const
Returns the size of an (Ethernet) MAC address (6).
-
void CMACAddress::Format(CString *pString) const
Sets
*pString
to the string representation of the MAC address.
WLAN support
The WLAN support in Circle is based on three elements:
Driver class
CBcm4343Device
for the WLAN hardwareTCP/IP networking subsystem, which is instantiated with the class
CNetSubSystem
WPA Supplicant library, which is built from the submodule hostap, and is instantiated via the wrapper class
CWPASupplicant
To enable WLAN support in Circle, these elements have to be created and initialized in this order. This is demonstrated in the WLAN sample. The third element is only required to use secure WLAN networks.
Note
The TCP/IP networking subsystem must be configured to use the WLAN device (NetDeviceTypeWLAN
) and must be initialized, without waiting for an IP address from the DHCP server (with the parameter FALSE
). Because the DHCP protocol requires WPA Supplicant to work, CNetSubSystem::Initialize()
would never return otherwise.
CWPASupplicant
#include <wlan/hostap/wpa_supplicant/wpasupplicant.h>
-
class CWPASupplicant
This class is a wrapper for the well-known WPA Supplicant application, which has been ported to Circle as a library. An instance of this class is required for connecting to secure (i.e. WPA2) WLAN networks. The WLAN hardware driver
CBcm4343Device
and the TCP/IP networking subsystem must already running, when WPA Supplicant is initialized.
-
CWPASupplicant::CWPASupplicant(const char *pConfigFile)
Creates an instance of this class.
pConfigFile
is the path to the configuration file (e.g. “SD:/wpa_supplicant.conf”).
-
boolean CWPASupplicant::Initialize(void)
Initializes the WPA Supplicant module and automatically starts to connect to one of the WLAN networks, which have been configured in the configuration file.
-
boolean CWPASupplicant::IsConnected(void) const
Returns
TRUE
, if a connection to a configured WLAN network is currently active.
Graphics
Circle provides several options for implementing graphical user interfaces (GUI) and for generating pixel and vector graphics on an attached HDMI or composite TV display. These options are described in this section.
C2DGraphics
The class C2DGraphics
is part of the Circle base library and can be used to generate pixel graphics on a frame buffer, which is provided by the class CBcmFrameBuffer
.
#include <circle/2dgraphics.h>
-
class C2DGraphics
This class is a software graphics library with VSync and hardware-accelerated double buffering.
-
C2DGraphics::C2DGraphics(unsigned nWidth, unsigned nHeight, boolean bVSync = TRUE, unsigned nDisplay = 0)
Creates on instance of this class.
nWidth
is the screen width in pixels (0 to detect).nHeight
is the screen height in pixels (0 to detect). SetbVSync
toTRUE
to enable VSync and HW double buffering.nDisplay
is the zero-based display number (for Raspberry Pi 4).
-
boolean C2DGraphics::Initialize(void)
Initializes the screen. Returns
TRUE
on success.
-
unsigned C2DGraphics::GetWidth(void) const
Returns the screen width in pixels.
-
unsigned C2DGraphics::GetHeight(void) const
Returns the screen height in pixels.
-
void C2DGraphics::ClearScreen(TScreenColor Color)
Clears the screen.
Color
is the color used to clear the screen (seeCScreenDevice::SetPixel()
).
-
void C2DGraphics::DrawRect(unsigned nX, unsigned nY, unsigned nWidth, unsigned nHeight, TScreenColor Color)
Draws a filled rectangle.
nX
is the start X coordinate.nY
is the start Y coordinate.nWidth
is the rectangle width.nHeight
is the rectangle height.Color
is the rectangle color.
-
void C2DGraphics::DrawRectOutline(unsigned nX, unsigned nY, unsigned nWidth, unsigned nHeight, TScreenColor Color)
Draws an unfilled rectangle (inner outline).
nX
is the start X coordinate.nY
is the start Y coordinate.nWidth
is the rectangle width.nHeight
is the rectangle height.Color
is the rectangle color.
-
void C2DGraphics::DrawLine(unsigned nX1, unsigned nY1, unsigned nX2, unsigned nY2, TScreenColor Color)
Draws a line.
nX1
is the start position X coordinate.nY1
is the start position Y coordinate.nX2
is the end position X coordinate.nY2
is the end position Y coordinate.Color
is the line color.
-
void C2DGraphics::DrawCircle(unsigned nX, unsigned nY, unsigned nRadius, TScreenColor Color)
Draws a filled circle.
nX
is the circle X coordinate.nY
is the circle Y coordinate.nRadius
is the circle radius.Color
is the circle color.
-
void C2DGraphics::DrawCircleOutline(unsigned nX, unsigned nY, unsigned nRadius, TScreenColor Color)
Draws an unfilled circle (inner outline).
nX
is the circle X coordinate.nY
is the circle Y coordinate.nRadius
is the circle radius.Color
is the circle color.
-
void C2DGraphics::DrawImage(unsigned nX, unsigned nY, unsigned nWidth, unsigned nHeight, TScreenColor *PixelBuffer)
Draws an image from a pixel buffer.
nX
is the image X coordinate.nY
is the image Y coordinate.nWidth
is the image width.nHeight
is the image height.PixelBuffer
is a pointer to the pixels.
-
void C2DGraphics::DrawImageTransparent(unsigned nX, unsigned nY, unsigned nWidth, unsigned nHeight, TScreenColor *PixelBuffer, TScreenColor TransparentColor)
Draws an image from a pixel buffer with transparent color.
nX
is the image X coordinate.nY
is the image Y coordinate.nWidth
is the image width.nHeight
is the image height.PixelBuffer
is a pointer to the pixels.TransparentColor
is the color to use for transparency.
-
void C2DGraphics::DrawImageRect(unsigned nX, unsigned nY, unsigned nWidth, unsigned nHeight, unsigned nSourceX, unsigned nSourceY, TScreenColor *PixelBuffer)
Draws an area of an image from a pixel buffer.
nX
is the image X coordinate.nY
is the image Y coordinate.nWidth
is the image width.nHeight
is the image height.nSourceX
is the source X coordinate in the pixel buffer.nSourceY
is the source Y coordinate in the pixel buffer.PixelBuffer
is a pointer to the pixels.
-
void C2DGraphics::DrawImageRectTransparent(unsigned nX, unsigned nY, unsigned nWidth, unsigned nHeight, unsigned nSourceX, unsigned nSourceY, unsigned nSourceWidth, unsigned nSourceHeight, TScreenColor *PixelBuffer, TScreenColor TransparentColor)
Draws an area of an image from a pixel buffer with transparent color.
nX
is the image X coordinate.nY
is the image Y coordinate.nWidth
is the image width.nHeight
is the image height.nSourceX
is the source X coordinate in the pixel buffer.nSourceY
is the source Y coordinate in the pixel buffer.nSourceWidth
is the source image width.nSourceHeight
is the source image height.PixelBuffer
is a pointer to the pixels.TransparentColor
is the color to use for transparency.
-
void C2DGraphics::DrawPixel(unsigned nX, unsigned nY, TScreenColor Color)
Draws a single pixel.
nX
is the pixel X coordinate.nY
is the pixel Y coordinate.Color
is the pixel color.
Note
If you need to draw a lot of pixels, consider using C2DGraphics::GetBuffer()
for better speed.
-
TScreenColor *C2DGraphics::GetBuffer(void)
Gets raw access to the drawing buffer. Returns a pointer to the buffer.
-
void C2DGraphics::UpdateDisplay(void)
Once everything has been drawn, updates the display to show the contents on screen. If VSync is enabled, this method is blocking until the screen refresh signal is received (every 16ms for 60 FPS refresh rate).
LVGL
The Light and Versatile Graphics Library (LVGL) v8.2.0 can be used with Circle. This library provides an API, which is based on the C language. See the LVGL documentation for details.
#include <lvgl/lvgl.h>
-
class CLVGL
This class is a wrapper for LVGL and has to be instantiated to use this graphics library. The wrapper class supports USB mouse or touchscreen input.
-
CLVGL::CLVGL(CScreenDevice *pScreen, CInterruptSystem *pInterrupt)
-
CLVGL::CLVGL(CBcmFrameBuffer *pFrameBuffer, CInterruptSystem *pInterrupt)
Create an instance of this class.
pScreen
orpFrameBuffer
reference the display to be used.pInterrupt
is a pointer to the system interrupt object.
-
void CLVGL::Update(boolean bPlugAndPlayUpdated = FALSE)
Updates the display. This has to be called continuously from the application main loop at
TASK_LEVEL
.bPlugAndPlayUpdated
must be set toTRUE
, if the application supports USB plug-and-play andCUSBHostController::UpdatePlugAndPlay()
returnedTRUE
too.
µGUI
The µGUI library can be used with Circle. This library provides an API, which is based on the C language. Download the Reference Guide for details.
#include <ugui/uguicpp.h>
-
class CUGUI
This class is a wrapper for µGUI and has to be instantiated to use this graphics library. The wrapper class supports USB mouse or touchscreen input.
-
CUGUI::CUGUI(CScreenDevice *pScreen)
Creates an instance of this class.
pScreen
references the display to be used.
-
void CUGUI::Update(boolean bPlugAndPlayUpdated = FALSE)
Updates the display. This has to be called continuously from the application main loop at
TASK_LEVEL
.bPlugAndPlayUpdated
must be set toTRUE
, if the application supports USB plug-and-play andCUSBHostController::UpdatePlugAndPlay()
returnedTRUE
too.
Accelerated graphics
The accelerated graphics support is described in the VC4 subsystem section.
VC4
The VC4 subsystem in addon/vc4 provides the VCHIQ driver as an interface to the audio and accelerated graphics services, which are offered by the Raspberry Pi firmware. The accelerated graphics support is not available on the Raspberry Pi 4 and with AARCH = 32
only. This section describes the components of the VC4 subsystem.
VCHIQ driver
#include <vc4/vchiq/vchiqdevice.h>
-
class CVCHIQDevice : public CLinuxDevice
This class is a driver for the VC host interface queue, which implements an interface to a number of service processes, which are running on the video processing unit (VPU) of the Raspberry Pi computers. Because this driver has been ported from Linux, it is based on the Linux kernel device driver emulation code in addon/linux. The API of the VCHIQ driver is based on the C language, and is not covered by this documentation.
-
CVCHIQDevice::CVCHIQDevice(CMemorySystem *pMemory, CInterruptSystem *pInterrupt)
Creates an instance of the VCHIQ driver class. There can be only one.
pMemory
andpInterrupt
are pointers to the Circle memory and interrupt system objects.
-
boolean CVCHIQDevice::Initialize(void)
Initializes the VCHIQ driver. Returns
TRUE
on success. This method is inherited from the base classCLinuxDevice
.
VCHIQ sound
The VCHIQ sound driver class CVCHIQSoundBaseDevice
is described in the Audio devices section.
Accelerated graphics
The accelerated graphics support in addon/vc4/interface has been ported from the Raspberry Pi OS (former Raspbian) userland libraries, which implement the following APIs:
EGL 1.4
OpenGL ES 1.1 and 2.0
OpenVG 1.1
Dispmanx (proprietary)
Please see this website for detailed information about the first three APIs, which are not specific to Circle and are based on the C language.
Note
The accelerated graphics support is not available on the Raspberry Pi 4 and with AARCH = 32
only.
Devices
This section describes the interfaces of the different device driver classes in Circle.
The Circle project does not provide a single centralized C++ header file. Instead the header file(s), which must be included for a specific class, function or macro definition are specified in the related subsection.
Device management
In Circle most devices are represented by two things:
By a device specific object, an instance of a class, which is derived from the class
CDevice
.By a device name, a C-string, which allows to retrieve a pointer to the device object, using the Circle device name service, which is implemented by the class
CDeviceNameService
.
Note
The I/O system of Circle is not as uniform as that of Linux, for example. Some device classes have specific interfaces, different from the well-known Read()
and Write()
interface and are not derived from CDevice
.
CDevice
#include <circle/device.h>
-
class CDevice
This class is the base class for most device classes in Circle.
-
virtual int CDevice::Read(void *pBuffer, size_t nCount)
Performs a read operation of up to
nCount
bytes from a device topBuffer
. Returns the number of read bytes or < 0 on failure.
-
virtual int CDevice::Write(const void *pBuffer, size_t nCount)
Performs a write operation of up to
nCount
bytes to a device frompBuffer
. Returns the number of written bytes or < 0 on failure.
-
virtual u64 CDevice::Seek(u64 ullOffset)
Sets the position of the read/write pointer of a device to the byte offset
ullOffset
. Returns the resulting offset, or(u64) -1
on failure. This method is only implemented by block devices, character devices always return failure.
-
virtual boolean CDevice::RemoveDevice(void)
Requests the remove of a device from the system for pseudo plug-and-play. This is only implemented for USB devices (e.g. for USB mass-storage devices). Returns
TRUE
on the successful removal of the device.
-
void RegisterRemovedHandler(TDeviceRemovedHandler *pHandler, void *pContext = 0)
Registers a callback, which is invoked, when this device is removed from the system in terms of hot-plugging.
pHandler
gets called, before the device object is deleted.pHandler
can be 0 to unregister a previously set handler.pContext
is a user pointer, which is handed over to the handler.
void TDeviceRemovedHandler (CDevice *pDevice, void *pContext);
Note
See the file doc/usb-plug-and-play.txt for detailed information on USB plug-and-play support in Circle!
CDeviceNameService
#include <circle/devicenameservice.h>
-
class CDeviceNameService
In Circle devices can be registered by name and retrieved later using the same name. This is implemented in the class
CDeviceNameService
.
Note
A device name usually consists of an alpha name prefix, followed by a decimal device index number, which is >= 1. Partitions on block devices have another partition index, which is >= 1 too. Sound devices do not have a device index number. Examples:
Device name |
Description |
---|---|
tty1 |
First screen device |
ukbd1 |
First USB keyboard device |
umsd1 |
First USB mass-storage device (e.g. flash drive) |
umsd1-1 |
First partition on the first USB mass-storage device |
sndpwm |
PWM sound device |
null |
Null device |
-
static CDeviceNameService *CDeviceNameService::Get(void)
Returns a pointer to the single
CDeviceNameService
instance in the system.
-
CDevice *CDeviceNameService::GetDevice(const char *pName, boolean bBlockDevice)
Returns a pointer to the device object of the device, with the name
pName
and the device typebBlockDevice
, or 0 if the device is not found.bBlockDevice
isTRUE
, if this is a block device, otherwise it is a character device.
-
CDevice *CDeviceNameService::GetDevice(const char *pPrefix, unsigned nIndex, boolean bBlockDevice)
Returns a pointer to the device object of the device, with the name prefix
pName
, the device indexnIndex
and the device typebBlockDevice
, or 0 if the device is not found.bBlockDevice
isTRUE
, if this is a block device, otherwise it is a character device. The resulting name consists of the name prefix followed by the decimal device index (e.g.umsd1
for the first USB mass-storage device).
-
void CDeviceNameService::ListDevices(CDevice *pTarget)
Generates a textual device name listing and writes it to the device
pTarget
.
-
void CDeviceNameService::AddDevice(const char *pName, CDevice *pDevice, boolean bBlockDevice)
Adds the pointer
pDevice
to a device object with the namepName
to the device name registry.bBlockDevice
isTRUE
, if this is a block device, otherwise it is a character device. This method is usually only used by device driver classes.
-
void CDeviceNameService::AddDevice(const char *pPrefix, unsigned nIndex, CDevice *pDevice, boolean bBlockDevice)
Adds the pointer
pDevice
to a device object with the name prefixpName
and device indexnIndex
to the device name registry.bBlockDevice
isTRUE
, if this is a block device, otherwise it is a character device. The resulting name consists of the name prefix followed by the decimal device index (e.g.umsd1
for the first USB mass-storage device). This method is usually only used by device driver classes.
-
void CDeviceNameService::RemoveDevice(const char *pName, boolean bBlockDevice)
Removes the device with the name
pName
and the device typebBlockDevice
from the device name registry.bBlockDevice
isTRUE
, if this is a block device, otherwise it is a character device. This method is usually only used by device driver classes.
-
void CDeviceNameService::RemoveDevice(const char *pPrefix, unsigned nIndex, boolean bBlockDevice)
Removes the device with the name prefix
pPrefix
, the device indexnIndex
and the device typebBlockDevice
from the device name registry.bBlockDevice
isTRUE
, if this is a block device, otherwise it is a character device. The resulting name consists of the name prefix followed by the decimal device index (e.g.umsd1
for the first USB mass-storage device). This method is usually only used by device driver classes.
Character devices
Character devices usually accept and/or deliver a stream of characters via Write()
and Read()
calls. In Circle some character devices use a register-able callback handler instead of the Read()
method, to deliver the received data. This makes time-consuming polling operations superfluous for these devices.
CScreenDevice
#include <circle/screen.h>
-
class CScreenDevice : public CDevice
This class can be used to write characters to the (usually HDMI) screen, which is connected to the Raspberry Pi computer. The screen is treated like a terminal and provides a number of control sequences (see
Write()
). This device has the name"ttyN"
(N >= 1) in the device name service.
-
CScreenDevice::CScreenDevice(unsigned nWidth, unsigned nHeight, boolean bVirtual = FALSE, unsigned nDisplay = 0)
Constructs an instance of
CScreenDevice
.nWidth
is the screen width andnHeight
the screen height in number of pixels. Set both parameters to 0 to auto-detect the default resolution of the screen, which is usually the maximum resolution of the used monitor.bVirtual
should be set toFALSE
in any case. The Raspberry Pi 4 supports more than one display.nDisplay
is the zero-based display number here. Multiple instances ofCScreenDevice
are possible here.
Note
You have to set max_framebuffers=2
in config.txt to use two displays on the Raspberry Pi 4.
-
boolean CScreenDevice::Initialize(void)
Initializes the instance of
CScreenDevice
and clears the screen. ReturnsTRUE
on success.
-
unsigned CScreenDevice::GetWidth(void) const
Returns the screen width in number of pixels.
-
unsigned CScreenDevice::GetHeight(void) const
Returns the screen height in number of pixels.
-
unsigned CScreenDevice::GetColumns(void) const
Returns the screen width in number of character columns.
-
unsigned CScreenDevice::GetRows(void) const
Returns the screen height in number of character rows.
-
int CScreenDevice::Write(const void *pBuffer, size_t nCount)
Writes
nCount
characters frompBuffer
to the screen. Returns the number of written characters. This method supports several escape sequences:Sequence
Description
Remarks
\E[B
Cursor down one line
\E[H
Cursor home
\E[A
Cursor up one line
\E[%d;%dH
Cursor move to row %1 and column %2
starting at 1
^H
Cursor left one character
\E[D
Cursor left one character
\E[C
Cursor right one character
^M
Carriage return
\E[J
Clear to end of screen
\E[K
Clear to end of line
\E[%dX
Erase %1 characters starting at cursor
^J
Carriage return/linefeed
\E[0m
End of bold, half bright, reverse mode
\E[1m
Start bold mode
\E[2m
Start half bright mode
\E[7m
Start reverse video mode
\E[27m
Same as \E[0m
\E[%dm
Set foreground color
%d = 30-37 or 90-97
\E[%dm
Set background color
%d = 40-47 or 100-107
^I
Move to next hardware tab
\E[?25h
Normal cursor visible
\E[?25l
Cursor invisible
\E[%d;%dr
Set scroll region from row %1 to %2
starting at 1
^X = Control character, \E = Escape (\x1b), %d = Numerical parameter (ASCII)
-
void CScreenDevice::SetPixel(unsigned nPosX, unsigned nPosY, TScreenColor Color)
Sets the pixel at position
nPosX, nPosY
(based on0, 0
) toColor
. The color value depends on the macro valueDEPTH
, which can be defined as 8, 16 (default) or 32 in include/circle/screen.h or Config.mk. Circle defines the following standard color values:BLACK_COLOR (black)
NORMAL_COLOR (white)
HIGH_COLOR (red)
HALF_COLOR (dark blue)
The following specific color values are defined:
RED_COLOR
GREEN_COLOR
YELLOW_COLOR
BLUE_COLOR
MAGENTA_COLOR
CYAN_COLOR
WHITE_COLOR
BRIGHT_BLACK_COLOR
BRIGHT_RED_COLOR
BRIGHT_GREEN_COLOR
BRIGHT_YELLOW_COLOR
BRIGHT_BLUE_COLOR
BRIGHT_MAGENTA_COLOR
BRIGHT_CYAN_COLOR
BRIGHT_WHITE_COLOR
-
COLOR16(r, g, b)
Defines a color value for
DEPTH == 16
. r/g/b can be 0-31.
-
COLOR32(r, g, b, alpha)
Defines a color value for
DEPTH == 32
. r/g/b can be 0-255. alpha is usually 255.
-
TScreenColor CScreenDevice::GetPixel(unsigned nPosX, unsigned nPosY)
Returns the pixel color value at position
nPosX, nPosY
(based on0, 0
).
-
void CScreenDevice::Rotor(unsigned nIndex, unsigned nCount)
Displays a rotating symbol in the upper right corner of the screen.
nIndex
is the index of the rotor to be displayed (0..3).nCount
is the phase (angle) of the current rotor symbol (0..3).
-
CBcmFrameBuffer *CScreenDevice::GetFrameBuffer(void)
Returns a pointer to the member of the type
CBcmFrameBuffer
, which can be used to directly manipulate the frame buffer.
CSerialDevice
#include <circle/serial.h>
-
class CSerialDevice : public CDevice
This class is a driver for the PL011-compatible UART(s) of the Raspberry Pi. The Raspberry Pi 4 provides five of these serial devices, the other models only one. This driver cannot be used for the Mini-UART (AUX). The GPIO mapping is as follows (SoC numbers):
nDevice
TXD
RXD
Support
0
GPIO14
GPIO15
All boards
0
GPIO32
GPIO33
Compute Modules
0
GPIO36
GPIO37
Compute Modules
1
None (AUX)
2
GPIO0
GPIO1
Raspberry Pi 4 only
3
GPIO4
GPIO5
Raspberry Pi 4 only
4
GPIO8
GPIO9
Raspberry Pi 4 only
5
GPIO12
GPIO13
Raspberry Pi 4 only
GPIO32/33 and GPIO36/37 can be selected with system option
SERIAL_GPIO_SELECT
. GPIO0/1 are normally reserved for the ID EEPROM. Handshake lines CTS and RTS are not supported.This device has the name
"ttySN"
(N >= 1) in the device name service, whereN = nDevice+1
.
Note
This driver can be used in two modes: polling or interrupt driven. The mode is selected with the parameter pInterruptSystem
of the constructor.
-
SERIAL_BUF_SIZE
This macro defines the size of the read and write ring buffers for the interrupt driver (default 2048). If you want to increase the buffer size, you have to specify a value, which is a power of two.
-
CSerialDevice::CSerialDevice(CInterruptSystem *pInterruptSystem = 0, boolean bUseFIQ = FALSE, unsigned nDevice = 0)
Constructs a
CSerialDevice
object. Multiple instances are possible on the Raspberry Pi 4.nDevice
selects the used serial device (see the table above).pInterruptSystem
is a pointer to interrupt system object, or 0 to use the polling driver. The interrupt driver uses the IRQ by default. SetbUseFIQ
toTRUE
to use the FIQ instead. This is recommended for higher baud rates.
-
boolean CSerialDevice::Initialize(unsigned nBaudrate = 115200, unsigned nDataBits = 8, unsigned nStopBits = 1, TParity Parity = ParityNone)
Initializes the serial device and sets the baud rate to
nBaudrate
bits per second.nDataBits
selects the number of data bits (5..8, default 8) andnStopBits
the number of stop bits (1..2, default 1).Parity
can beCSerialDevice::ParityNone
(default),CSerialDevice::ParityOdd
orCSerialDevice::ParityEven
. ReturnsTRUE
on success.
-
int CSerialDevice::Write(const void *pBuffer, size_t nCount)
Writes
nCount
bytes frompBuffer
to be sent out via the serial device. Returns the number of bytes, successfully sent or queued for send, or < 0 on error. The following errors are defined:
-
SERIAL_ERROR_BREAK
-
SERIAL_ERROR_OVERRUN
-
SERIAL_ERROR_FRAMING
-
SERIAL_ERROR_PARITY
Returned from
Write()
andRead()
as a negative value. Please note, that these defined values are positive. You have to precede them with a minus for comparison.
-
int CSerialDevice::Read(void *pBuffer, size_t nCount)
Returns a maximum of
nCount
bytes, which have been received via the serial device, inpBuffer
. The returnedint
value is the number of received bytes, 0 if data is not available, or < 0 on error (seeWrite()
).
-
unsigned CSerialDevice::GetOptions(void) const
Returns the current serial options mask.
-
void CSerialDevice::SetOptions(unsigned nOptions)
Sets the serial options mask to
nOptions
. These options are defined:
-
SERIAL_OPTION_ONLCR
Translate NL to NL+CR on output (default)
-
void CSerialDevice::RegisterMagicReceivedHandler(const char *pMagic, TMagicReceivedHandler *pHandler)
Registers a magic received handler
pHandler
, which is called, when the stringpMagic
is found in the received data.pMagic
must remain valid after return from this method. This method does only work with interrupt driver.
-
typedef void CSerialDevice::TMagicReceivedHandler(void)
CUSBKeyboardDevice
#include <circle/usb/usbkeyboard.h>
-
class CUSBKeyboardDevice : public CUSBHIDDevice
This class is a driver for USB standard keyboards. An instance of this class is automatically created, when a compatible USB keyboard is found in the USB device enumeration process. Therefore only the class methods needed to use the keyboard by an application are described here, not the methods used for initialization. This device has the name
"ukbdN"
(N >= 1) in the device name service.
Note
This driver class supports two keyboard modes: cooked and raw mode. In cooked mode the driver reports ISO-8859-1 character strings and the keyboard LEDs are handled automatically. There are six available keyboard maps (DE, ES, FR, IT, UK, US), which can be selected with the DEFAULT_KEYMAP
configurable system option or the keymap=
setting in the file cmdline.txt on the SD card.
In raw mode the driver reports the raw USB keyboard codes and modifier information and the LEDs have to be set manually by the application.
-
void CUSBKeyboardDevice::RegisterKeyPressedHandler(TKeyPressedHandler *pKeyPressedHandler)
Registers a function, which gets called, when a key is pressed in cooked mode:
-
typedef void TKeyPressedHandler(const char *pString)
pString
points to a C-string, which contains the ISO-8859-1 code of the pressed key. This is normally only one character, but can be one of the following control sequences for special purpose keys:Sequence
Key
\E
Escape
\177
Backspace
^I
Tabulator
^J
Return
\E[2~
Insert
\E[1~
Home
\E[5~
PageUp
\E[3~
Delete
\E[4~
End
\E[6~
PageDown
\E[A
Up
\E[B
Down
\E[D
Left
\E[C
Right
\E[[A
F1
\E[[B
F2
\E[[C
F3
\E[[D
F4
\E[[E
F5
\E[17~
F6
\E[18~
F7
\E[19~
F8
\E[20~
F9
\E[G
KP_Center
^X = Control character, \E = Escape (\x1b), \nnn = Octal code
-
void CUSBKeyboardDevice::RegisterSelectConsoleHandler(TSelectConsoleHandler *pSelectConsoleHandler)
Registers a function, which gets called, when the Alt key is pressed together with a function key F1 to F12 in cooked mode. This is used to select the console in some systems.
-
typedef void TSelectConsoleHandler(unsigned nConsole)
nConsole
is the number of the console to select (0-11).
-
void CUSBKeyboardDevice::RegisterShutdownHandler(TShutdownHandler *pShutdownHandler)
Registers a function, which gets called, when the Ctrl, Alt and Del keys are pressed together in cooked mode. This is used to shutdown or reboot some systems.
-
typedef void TShutdownHandler(void)
-
void CUSBKeyboardDevice::UpdateLEDs(void)
In cooked mode this method has to be called from TASK_LEVEL from time to time, so that the status of the keyboard LEDs can be updated.
-
u8 CUSBKeyboardDevice::GetLEDStatus(void) const
Returns the LED status mask of the keyboard in cooked mode, with the following bit masks:
LED_NUM_LOCK
LED_CAPS_LOCK
LED_SCROLL_LOCK
-
boolean CUSBKeyboardDevice::SetLEDs(u8 ucStatus)
Sets the keyboard LEDs according to the bit mask values listed under
GetLEDStatus()
. This method can be called on TASK_LEVEL only. It works in cooked and raw mode.
-
void CUSBKeyboardDevice::RegisterKeyStatusHandlerRaw(TKeyStatusHandlerRaw *pKeyStatusHandlerRaw, boolean bMixedMode = FALSE)
Registers a function, which gets called to report the keyboard status in raw mode. If
bMixedMode
isFALSE
, then the cooked mode handlers are ignored. You can set it toTRUE
to be able to use cooked mode and raw mode handlers together.
Note
It depends on the used USB keyboard, if the raw status handler gets called on status changes only or repeatedly after some delay too. The application must be able to handle both cases.
-
typedef void TKeyStatusHandlerRaw(unsigned char ucModifiers, const unsigned char RawKeys[6])
RawKeys
contains up to six raw USB keyboard codes or zero in each byte.ucModifiers
contains a mask of the pressed modifier keys, with the following bit masks:LCTRL
LSHIFT
ALT
LWIN
RCTRL
RSHIFT
ALTGR
RWIN
CMouseDevice
#include <circle/input/mouse.h>
-
class CMouseDevice : public CDevice
This class is the generic mouse interface device. An instance of this class is automatically created, when a compatible USB mouse or USB gamepad with touchpad is found in the USB device enumeration process. Therefore only the class methods, needed to use the mouse by an application, are described here, not the method used for creation. This device has the name
"mouseN"
(N >= 1) in the device name service.
Note
This class supports two mouse modes: cooked and raw mode. In cooked mode a mouse cursor is shown on the screen and automatically controlled by the driver, which reports several mouse events (down, up, move, wheel).
In raw mode the driver directly reports the raw mouse displacement, button and wheel information.
-
boolean CMouseDevice::Setup(unsigned nScreenWidth, unsigned nScreenHeight)
Setup mouse device in cooked mode.
nScreenWidth
andnScreenHeight
are the width and height of the screen in pixels. ReturnsFALSE
on failure. This method must be called first in the setup process for a mouse in cooked mode.
-
void CMouseDevice::RegisterEventHandler(TMouseEventHandler *pEventHandler)
Registers an mouse event handler in cooked mode.
pEventHandler
is a pointer to the event handler with the following prototype:
-
typedef void TMouseEventHandler(TMouseEvent Event, unsigned nButtons, unsigned nPosX, unsigned nPosY, int nWheelMove)
nPosX
is the X-coordinate of the current mouse cursor position in pixels (0 is on the left border).nPosY
is the Y-coordinate of the position in pixels (0 is on the top border). These parameters are always valid (also in button and wheel events).Event
is the reported mouse event with these possible values:
-
enum TMouseEvent
Event
Reports
Parameter
MouseEventMouseDown
one button, which has been pressed
nButtons
MouseEventMouseUp
one button, which has been released
nButtons
MouseEventMouseMove
a mouse move to a new screen position
nPosX
,nPosY
MouseEventMouseWheel
a wheel move (raw displacement -/+)
nWheelMove
-
MOUSE_BUTTON_LEFT
-
MOUSE_BUTTON_RIGHT
-
MOUSE_BUTTON_MIDDLE
-
MOUSE_BUTTON_SIDE1
-
MOUSE_BUTTON_SIDE2
Bit masks for the
nButtons
parameter.
-
boolean CMouseDevice::SetCursor(unsigned nPosX, unsigned nPosY)
Sets the mouse cursor to a specific screen position in cooked mode.
nPosX
is the X-coordinate of the position in pixels (0 is on the left border).nPosY
is the Y-coordinate of the position in pixels (0 is on the top border). ReturnsFALSE
on failure.
-
boolean CMouseDevice::ShowCursor(boolean bShow)
Switches the mouse cursor on the screen on or off in cooked mode. Set
bShow
toTRUE
to show the mouse cursor. Returns the previous state.
-
void CMouseDevice::UpdateCursor(void)
This method must be called frequently from
TASK_LEVEL
in cooked mode to update the mouse cursor on screen.
-
void CMouseDevice::RegisterStatusHandler(TMouseStatusHandler *pStatusHandler)
Registers the mouse status handler in raw mode.
pStatusHandler
is a pointer to the status handler with the following prototype:
-
typedef void TMouseStatusHandler(unsigned nButtons, int nDisplacementX, int nDisplacementY, int nWheelMove)
nButtons
is the raw button mask reported from the mouse device. Use the same bit masksMOUSE_BUTTON_LEFT
etc. listed above.nDisplacementX
andnDisplacementY
are the raw displacement values reported from the mouse device, with these limits:
-
MOUSE_DISPLACEMENT_MIN
-
MOUSE_DISPLACEMENT_MAX
-
unsigned CMouseDevice::GetButtonCount(void) const
Returns the number of supported buttons for this mouse device.
-
boolean CMouseDevice::HasWheel(void) const
Returns
TRUE
, if the mouse supports a mouse wheel.
CUSBGamePadDevice
#include <circle/usb/usbgamepad.h>
-
class CUSBGamePadDevice : public CUSBHIDDevice
This class is the base class for USB gamepad drivers and the generic application interface for USB gamepads. There are a number of different derived classes, which implement the drivers for specific gamepads. Circle automatically creates an instance of the right class, when a compatible USB gamepad is found in the USB device enumeration process. Therefore only the class methods, needed to use the gamepad by an application, are described here, not the methods used for initialization. This device has the name
"upadN"
(N >= 1) in the device name service.
Note
Circle supports gamepads, which are compatible with the USB HID-class specification and some other gamepads. To use a specific gamepad an application must normally know the mapping of the gamepad controls (buttons, axes etc.) to the gamepad report items. This mapping is not defined by the specification, but known for some widely available gamepads. A supported gamepad with a known mapping is called a “known gamepad” here and its driver offers additional services. The properties of a gamepad can be requested using GetProperties()
.
The sample/27-usbgamepad is working with all supported gamepads, but has limited function. The sample/37-showgamepad is only working with with known gamepads with more function.
-
struct TGamePadState
This structure is used to report the current state of the gamepad controls to the application. It can be fetched using
GetInitialState()
or by registering a status handler usingRegisterStatusHandler()
.
#define MAX_AXIS 16
#define MAX_HATS 6
struct TGamePadState
{
int naxes; // Number of available axes and analog buttons
struct
{
int value; // Current position value
int minimum; // Minimum position value (normally 0)
int maximum; // Maximum position value (normally 255)
}
axes[MAX_AXIS]; // Array of axes and analog buttons
int nhats; // Number of available hat controls
int hats[MAX_HATS]; // Current position value of hat controls
int nbuttons; // Number of available digital buttons
unsigned buttons; // Current status of digital buttons (bit mask)
int acceleration[3]; // Current state of acceleration sensor (x, y, z)
int gyroscope[3]; // Current state of gyroscope sensor (x, y, z)
};
#define GAMEPAD_AXIS_DEFAULT_MINIMUM 0
#define GAMEPAD_AXIS_DEFAULT_MAXIMUM 255
-
enum TGamePadButton
Defines bit masks for the
TGamePadState::buttons
field for known gamepads. If the digital button is pressed, the respective bit is set. The following buttons are defined:Digital button
Alias
Comment
GamePadButtonGuide
GamePadButtonXbox, GamePadButtonPS, GamePadButtonHome
GamePadButtonLT
GamePadButtonL2, GamePadButtonLZ
GamePadButtonRT
GamePadButtonR2, GamePadButtonRZ
GamePadButtonLB
GamePadButtonL1, GamePadButtonL
GamePadButtonRB
GamePadButtonR1, GamePadButtonR
GamePadButtonY
GamePadButtonTriangle
GamePadButtonB
GamePadButtonCircle
GamePadButtonA
GamePadButtonCross
GamePadButtonX
GamePadButtonSquare
GamePadButtonSelect
GamePadButtonBack, GamePadButtonShare, GamePadButtonCapture
GamePadButtonL3
GamePadButtonSL
left axis button
GamePadButtonR3
GamePadButtonSR
right axis button
GamePadButtonStart
GamePadButtonOptions
optional
GamePadButtonUp
GamePadButtonRight
GamePadButtonDown
GamePadButtonLeft
GamePadButtonPlus
optional
GamePadButtonMinus
optional
GamePadButtonTouchpad
optional
-
GAMEPAD_BUTTONS_STANDARD
-
GAMEPAD_BUTTONS_ALTERNATIVE
-
GAMEPAD_BUTTONS_WITH_TOUCHPAD
Number of digital buttons (19, 21 or 22) for known gamepads with different properties.
-
enum TGamePadAxis
Defines indices for the
TGamePadState::axes
field for known gamepads. This field covers the state information of axes and analog buttons. The following axes are defined:Axes
Alias
GamePadAxisLeftX
GamePadAxisLeftY
GamePadAxisRightX
GamePadAxisRightY
GamePadAxisButtonLT
GamePadAxisButtonL2
GamePadAxisButtonRT
GamePadAxisButtonR2
GamePadAxisButtonUp
GamePadAxisButtonRight
GamePadAxisButtonDown
GamePadAxisButtonLeft
GamePadAxisButtonL1
GamePadAxisButtonR1
GamePadAxisButtonTriangle
GamePadAxisButtonCircle
GamePadAxisButtonCross
GamePadAxisButtonSquare
-
unsigned CUSBGamePadDevice::GetProperties(void)
Returns the properties of the gamepad as a bit mask of
TGamePadProperty
constants, which are:Constant
Description
GamePadPropertyIsKnown
is a known gamepad
GamePadPropertyHasLED
supports
SetLEDMode()
GamePadPropertyHasRGBLED
if set,
GamePadPropertyHasLED
is set tooGamePadPropertyHasRumble
supports
SetRumbleMode()
GamePadPropertyHasGyroscope
provides sensor info in
TGamePadState
GamePadPropertyHasTouchpad
has touchpad with button
GamePadPropertyHasAlternativeMapping
has additional +/- buttons, no START button
-
const TGamePadState *CUSBGamePadDevice::GetInitialState(void)
Returns a pointer to the current gamepad state. This allows to initially request the information about the different gamepad controls. The control’s state fields may have some default value, when a report from the gamepad has not been received yet.
GetReport()
is an deprecated alias for this method.
-
void CUSBGamePadDevice::RegisterStatusHandler(TGamePadStatusHandler *pStatusHandler)
Registers a handler function to be called on gamepad state changes.
pStatusHandler
is a pointer to this function, with this prototype:
-
typedef void TGamePadStatusHandler(unsigned nDeviceIndex, const TGamePadState *pGamePadState)
nDeviceIndex
is the zero-based device index of this gamepad. The gamepad with the name"upadN"
(N >= 1) in the device name service has the device indexN-1
.pGamePadState
is a pointer to the current gamepad state.
-
boolean CUSBGamePadDevice::SetLEDMode(TGamePadLEDMode Mode)
Sets LED(s) on gamepads with multiple uni-color LEDs.
Mode
selects the LED mode to be set. ReturnsTRUE
if the LED mode is supported and was successfully set. A gamepad may support only a subset of the definedTGamePadLEDMode
modes:GamePadLEDModeOff
GamePadLEDModeOn1
GamePadLEDModeOn2
GamePadLEDModeOn3
GamePadLEDModeOn4
GamePadLEDModeOn5
GamePadLEDModeOn6
GamePadLEDModeOn7
GamePadLEDModeOn8
GamePadLEDModeOn9
GamePadLEDModeOn10
-
boolean CUSBGamePadDevice::SetLEDMode(u32 nRGB, u8 uchTimeOn, u8 uchTimeOff)
Sets the LED on gamepads with a single flash-able RGB-color LED. The property bit
GamePadPropertyHasRGBLED
is set, if this method is supported by a gamepad.nRGB
is the color value to be set (0x00rrggbb).uchTimeOn
is the duration, while the LED is on in 1/100 seconds.uchTimeOff
is the duration, while the LED is off in 1/100 seconds. ReturnsTRUE
, if the operation was successful.
-
boolean CUSBGamePadDevice::SetRumbleMode(TGamePadRumbleMode Mode)
Sets the rumble mode
Mode
, if the gamepad supports it (GamePadPropertyHasRumble
is set). ReturnsTRUE
, if the operation was successful. The following modes are defined:GamePadRumbleModeOff
GamePadRumbleModeLow
GamePadRumbleModeHigh
CUSBSerialDevice
#include <circle/usb/usbserial.h>
-
class CUSBSerialDevice : public CUSBFunction
This class is the base class for USB serial device (aka interface, adapter) drivers and the generic application interface for USB serial devices. There are a number of different derived classes, which implement the drivers for specific devices. Circle automatically creates an instance of the appropriate class, when a compatible USB serial device is found in the USB device enumeration process. Therefore only the class methods, needed to use the USB serial device by an application, are described here, not the methods used for initialization. This device has the name
"uttyN"
(N >= 1) in the device name service.
Note
Circle currently supports USB serial devices, which are compatible with the USB CDC-class specification (interfaces 2-2-0 and 2-2-1) and other devices, which use the following controllers: CH341, CP2102, FT231x, PL2303.
There are many different combinations of USB vendor and device IDs for these devices and Circle supports only a small subset of these combinations, which were available for tests. If you have a USB serial device, which is not detected, there is still some chance, that the device can work with a Circle driver. You have to add the vendor/device ID combination of your device to the array DeviceIDTable[]
at the end of the respective source file lib/usb/usbserial*.cpp and test it. Please report newly found vendor/device ID combinations and the used driver!
-
int CUSBSerialDevice::Read(void *pBuffer, size_t nCount)
-
int CUSBSerialDevice::Write(const void *pBuffer, size_t nCount)
Reads/writes data from/to the USB serial device (see
CDevice
).
-
boolean CUSBSerialDevice::SetBaudRate(unsigned nBaudRate)
Sets the interface speed to a specific baud (bit) rate.
nBaudRate
is the rate in bits per second. ReturnsTRUE
on success.
-
boolean CUSBSerialDevice::SetLineProperties(TUSBSerialDataBits DataBits, TUSBSerialParity Parity, TUSBSerialStopBits StopBits)
Sets the communication parameters number of data bits (
DataBits
), parity (Parity
) and number of stop bits (StopBits
) to the following values. ReturnsTRUE
on success.
enum TUSBSerialDataBits
{
USBSerialDataBits5 = 5,
USBSerialDataBits6 = 6,
USBSerialDataBits7 = 7,
USBSerialDataBits8 = 8,
};
enum TUSBSerialStopBits
{
USBSerialStopBits1 = 1,
USBSerialStopBits2 = 2,
};
enum TUSBSerialParity
{
USBSerialParityNone,
USBSerialParityOdd,
USBSerialParityEven,
};
CUSBPrinterDevice
#include <circle/usb/usbprinter.h>
-
class CUSBPrinterDevice : public CUSBFunction
This class is a simple driver for printers with USB interface. Only printers are supported, which are by default able to print ASCII characters on their own, not GDI printers. There is only one method of interest for applications, which writes the characters out to the printer. The printer device has the name
"uprnN"
(N >= 1) in the device name service.
-
int CUSBPrinterDevice::Write(const void *pBuffer, size_t nCount)
See
CDevice::Write()
.
CTouchScreenDevice
#include <circle/input/touchscreen.h>
-
class CTouchScreenDevice : public CDevice
This class is the generic touchscreen interface device. An instance of this class is automatically created, when a compatible USB touchscreen is found in the USB device enumeration process. When the class
CRPiTouchScreen
is manually instantiated, it is created too. This device has the name"touchN"
(N >= 1) in the device name service.
-
void CTouchScreenDevice::Update(void)
This method must be called about 60 times per second. This is required for the Raspberry Pi official touchscreen only, but to be prepared for any touchscreen, you should call it in any case.
-
void CTouchScreenDevice::RegisterEventHandler(TTouchScreenEventHandler *pEventHandler)
Registers a handler function, which will be called on events from the touchscreen. The prototype of the handler is:
-
typedef void TTouchScreenEventHandler(TTouchScreenEvent Event, unsigned nID, unsigned nPosX, unsigned nPosY)
Event
specifies the received event.nID
is an zero based identifier of the finger (for multi-touch). This first finger has always the ID zero.nPosX
andnPosY
specify the pixel position of the finger on the screen (for finger down and move events), where(0,0)
is the top left position. The following touchscreen events are defined:
-
enum TTouchScreenEvent
TouchScreenEventFingerDown
TouchScreenEventFingerUp
TouchScreenEventFingerMove
-
boolean CTouchScreenDevice::SetCalibration(const unsigned Coords[4], unsigned nWidth, unsigned nHeight)
Sets the calibration parameters for the touchscreen.
Coords
are the usable coordinates (min-x, max-x, min-y, max-y) of the touchscreen.nWidth
is the physical screen width andnHeight
the height in number of pixels. ReturnsTRUE
, if the calibration information is valid.
Note
The calibration parameters for a touchscreen can be determined with the Touchscreen calibrator.
CRPiTouchScreen
#include <circle/input/rpitouchscreen.h>
-
class CRPiTouchScreen
This class is a driver for the official Raspberry Pi touchscreen. If you want to use this touchscreen, you have to create an instance of this class and initialize it. For the further use of this touchscreen an instance of the class
CTouchScreenDevice
is automatically created.
-
RPITOUCH_SCREEN_MAX_POINTS
The maximum number of detected fingers on the touchscreen (10).
-
boolean CRPiTouchScreen::Initialize(void)
Initializes the driver. Returns
TRUE
on success.
Note
The driver cannot detect, if an official Raspberry Pi touchscreen is actually connected. Normally it returns TRUE
in any case.
CConsole
#include <circle/input/console.h>
-
class CConsole : public CDevice
This class implements a console with input and output stream and a line editor using the screen
tty1
and USB keyboardukbd1
devices or alternate device(s) (e.g. serial interface). The console device itself has the nameconsole
in the device name service. The sample/32-i2cshell demonstrates, how this class can be used to implement a simple shell.
Note
This class does not create instances of the devices, which are used for input and output. This has to be done by the application. The device ukbd1
is created in the USB device enumeration process, when an USB keyboard is found.
-
CConsole::CConsole(CDevice *pAlternateDevice = 0, boolean bPlugAndPlay = FALSE)
Creates an instance of this class.
pAlternateDevice
is an alternate device to be used, if the USB keyboard is not attached (default none).bPlugAndPlay
must be set toTRUE
to enable USB plug-and-play support for the console. This constructor is mandatory for USB plug-and-play operation.
-
CConsole::CConsole(CDevice *pInputDevice, CDevice *pOutputDevice)
Creates an instance of this class.
pInputDevice
is the device used for input (instead of the USB keyboard) andpOutputDevice
is the device used for output (instead of the screen).
-
boolean CConsole::Initialize(void)
Initializes the console class. Returns
TRUE
, if the operation has been successful.
-
void CConsole::UpdatePlugAndPlay(void)
Updates the USB plug-and-play configuration. This method must be called continuously, if the USB-plug-and-play support has been enabled in the constructor.
-
boolean CConsole::IsAlternateDeviceUsed(void) const
Returns
TRUE
, if the alternate device is used instead of screen/USB keyboard?
-
int CConsole::Read(void *pBuffer, size_t nCount)
See
CDevice::Read()
. This method does not block! It has to be called until!= 0
is returned.
-
int CConsole::Write(const void *pBuffer, size_t nCount)
See
CDevice::Write()
.
-
void CConsole::SetOptions(unsigned nOptions)
Sets the console options bit mask to
nOptions
.The following bits are defined:
-
CONSOLE_OPTION_ICANON
Canonic input using a line editor is enabled (default).
-
CONSOLE_OPTION_ECHO
Echo input to output is enabled (default).
CNullDevice
#include <circle/nulldevice.h>
-
class CNullDevice : public CDevice
This class implements the null device, which accepts all written characters and returns 0 (EOF) on read. It can be used instead of other character device classes, for instance as target for the System log. This device has the name
"null"
in the device name service.
-
int CNullDevice::Read(void *pBuffer, size_t nCount)
Returns always 0 (EOF).
-
int CNullDevice::Write(const void *pBuffer, size_t nCount)
Returns the number of written bytes, but ignores them.
Block devices
Block devices provide the access to physical or logical drives (e.g. SD card, USB flash drive). They allow to read and write consecutive blocks of bytes of a fixed block size. Circle supports only block devices with a size of 512 bytes. All block devices provide the following methods, which are derived from the class CDevice
. The detailed class descriptions below list additional class-specific methods only.
Method |
Purpose |
Description |
---|---|---|
Read() |
read block(s) from device |
|
Write() |
write block(s) to device |
|
Seek() |
set read/write pointer position |
CEMMCDevice
#include <SDCard/emmc.h>
-
class CEMMCDevice : public CDevice
This class provides the physical access to SD cards and to embedded MMC memory on the Compute Module 4. This class has to be manually instantiated, if an application wants to access one of these devices. This is demonstrated in addon/SDCard/sample. There can be only one instance of this device, which has the name
emmc1
in the device name service.This class has drivers for two different interfaces, the SDHOST interface and the EMMC interface. The SDHOST interface is enabled by default on the Raspberry Pi 1-3 and Zero, when the system option
REALTIME
is not enabled. On the Raspberry Pi 4 the EMMC interface is used in any case, but can be used on the earlier models with the system optionNO_SDHOST
too. This is not possible, when you want to access the on-board WLAN device at the same time. To access the embedded MMC on the Compute Module 4, the system optionUSE_EMBEDDED_MMC_CM4
has to be enabled.
-
CEMMCDevice::CEMMCDevice(CInterruptSystem *pInterruptSystem, CTimer *pTimer, CActLED *pActLED = 0)
Creates the instance of this class.
pInterruptSystem
is a pointer to the system interrupt object.pTimer
is a pointer to the system timer object.pActLED
can be specified to use the green Activity LED to inform the user, when the SD card is currently accessed. This is optional.
-
boolean CEMMCDevice::Initialize(void)
Initializes the EMMC or SDHOST device and detects the inserted SD card. Returns
TRUE
on success.
-
const u32 *CEMMCDevice::GetID(void)
Returns a pointer to the 32 byte (four
u32
words) long identifier of the inserted SD card. This information can be used to recognize a specific SD card again and is only valid, whenInitialize()
was successfully called before.
CUSBBulkOnlyMassStorageDevice
#include <circle/usb/usbmassdevice.h>
-
class CUSBBulkOnlyMassStorageDevice : public CUSBFunction
This class provides the physical access to USB mass-storage devices (e.g. flash drive, hard disk), which support the USB Mass Storage Bulk Only 1.0 specification. An instance of this class is automatically created in the USB device enumeration process, when a compatible USB device (interface 8-6-50) is found. These devices have the name
umsdN
(N >= 1) in the device name service.
-
unsigned CUSBBulkOnlyMassStorageDevice::GetCapacity(void) const
Returns the capacity of the device in number of 512 Byte blocks.
Note
Circle supports USB mass-storage devices with up to 2 TBytes capacity.
CPartition
#include <circle/fs/partition.h>
-
class CPartition : public CDevice
This class encapsulates one primary partition of a block device with Master Boot Record (MBR). An instance of this class is automatically created, when a block device object is initialized and a primary partition is found, when the MBR is scanned. Extended partitions (partition types 0x05 and 0x0F) and EFI partitions (type 0xEF) will be ignored in this process. These partition devices have the name
DEV-N
(N >= 1) in the device name service, where DEV is the name of the physical block device. For example the first found partition on a SD card has the nameemmc1-1
. This class only supports the standard methods of theCDevice
class.
Note
These partition devices are only accessed by the Circle-native FAT filesystem support (class CFATFileSystem
), but not by the FatFs library, which implements its own MBR management.
Audio devices
Circle supports the generation of sound via several hardware (PWM, I2S, HDMI) and software (VCHIQ) interfaces. It allows to capture sound data via the I2S hardware interface. Furthermore it is able to exchange MIDI data via USB and via a serial interface (UART). The latter has to be implemented in the application using the class CSerialDevice
.
The base class of all sound generating and capturing devices is CSoundBaseDevice
. The following table lists the provided classes for the different interfaces. The higher level support provides an additional conversion function for sound data in different formats as an example, which can be easily adapted for other sound classes.
Interface |
Connector |
Low level support |
Higher level support |
---|---|---|---|
PWM |
3.5” headphone jack |
CPWMSoundBaseDevice |
CPWMSoundDevice |
I2S |
GPIO header |
CI2SSoundBaseDevice |
|
HDMI |
HDMI(0) |
CHDMISoundBaseDevice |
|
VCHIQ |
HDMI or headphone jack |
CVCHIQSoundBaseDevice |
CVCHIQSoundDevice |
Several sample programs demonstrate functions of the different audio devices:
sample/12-pwmsound (playback a short sound sample using the PWM sound device)
sample/29-miniorgan (using the PWM, HDMI or I2S sound device, USB or serial MIDI)
sample/34-sounddevices (integrating multiple sound devices in one application)
sample/42-i2sinput (I2S to PWM sound data converter)
addon/vc4/sound/sample (HDMI or PWM sound support via VCHIQ interface)
The separate project MiniSynth Pi is a more extensive example for an application, which generates sound via the PWM or I2S interfaces in a multi-core environment, controlled with an USB or serial MIDI stream.
CSoundBaseDevice
#include <circle/soundbasedevice.h>
-
class CSoundBaseDevice : public CDevice
This class is the base for all sound generating and capturing classes in Circle. Normally it is not used directly in applications, but instead the derived class for the used interface is instantiated. Because this base class defines the common interface for all sound classes, it is described here first.
This class provides methods to start and stop the sound output and input, and to setup and manipulate one sound queue for each direction. Applications can use these queue(s) to provide/retrieve sound data with
Write()
and/orRead()
. Alternatively they can override the methodsGetChunk()
and/orPutChunk()
to directly write/read the audio samples to/from a provided DMA buffer.
Important
In a multi-core environment all methods, except if otherwise noted, have to be called or will be called (for callbacks) on CPU core 0.
Device activation
-
virtual boolean CSoundBaseDevice::Start(void)
Starts the transmission of sound data and initializes the device at the first call. Returns
TRUE
, if the operation was successful?
-
virtual void CSoundBaseDevice::Cancel(void)
Cancels the transmission of sound data. Cancel takes effect after a short delay.
-
virtual boolean CSoundBaseDevice::IsActive(void) const
Returns
TRUE
, if sound data transmission is currently running? This method can be called on any CPU core.
Output queue
These methods are used to output sound using a write queue. They are not used, if GetChunk()
is overwritten instead.
-
boolean CSoundBaseDevice::AllocateQueue(unsigned nSizeMsecs)
Allocates the queue used for
Write()
.nSizeMsecs
is the size of the queue in milliseconds duration of the stream.
-
boolean CSoundBaseDevice::AllocateQueueFrames(unsigned nSizeFrames)
Allocates the queue used for
Write()
.nSizeFrames
is the size of the queue in number of audio frames.
-
void CSoundBaseDevice::SetWriteFormat(TSoundFormat Format, unsigned nChannels = 2)
Sets the format of sound data provided to
Write()
toFormat
.nChannels
must be 1 (Mono) or 2 (Stereo). The following (interleaved little endian) write formats are allowed:SoundFormatUnsigned8
SoundFormatSigned16
SoundFormatSigned24 (occupies 3 bytes)
SoundFormatSigned24_32 (occupies 4 bytes)
-
int CSoundBaseDevice::Write(const void *pBuffer, size_t nCount)
Appends audio samples from
pBuffer
to the output queue.nCount
is the size of the buffer in bytes and must be a multiple of the frame size. Returns the number of bytes from the buffer, which have to be consumed successfully. This value may be smaller thannCount
, in which case some frames have been ignored. This method can be called on any CPU core.
-
unsigned CSoundBaseDevice::GetQueueSizeFrames(void)
Returns the output queue size in number of frames. This method can be called on any CPU core.
-
unsigned CSoundBaseDevice::GetQueueFramesAvail(void)
Returns the number of frames currently available in the output queue, which are waiting to be sent to the hardware interface. This method can be called on any CPU core.
-
void CSoundBaseDevice::RegisterNeedDataCallback(TSoundDataCallback *pCallback, void *pParam)
Registers the callback function
pCallback
, which is called, when more sound data is needed, which means that at least half of the queue is empty.pParam
is a user parameter to be handed over to the callback. The callback function has the following prototype:
-
typedef void TSoundDataCallback(void *pParam)
pParam
is the user parameter, which has been handed over toRegisterNeedDataCallback()
.
Input queue
These methods are used to input sound data using a read queue. They are not used, if PutChunk()
is overwritten instead.
-
boolean CSoundBaseDevice::AllocateReadQueue(unsigned nSizeMsecs)
Allocates the queue used for
Read()
.nSizeMsecs
is the size of the queue in milliseconds duration of the stream.
-
boolean CSoundBaseDevice::AllocateReadQueueFrames(unsigned nSizeFrames)
Allocates the queue used for
Read()
.nSizeFrames
is the size of the queue in number of audio frames.
-
void CSoundBaseDevice::SetReadFormat(TSoundFormat Format, unsigned nChannels = 2, boolean bLeftChannel = TRUE)
Sets the format of sound data returned from
Read()
toFormat
.nChannels
must be 1 (Mono) or 2 (Stereo). IfbLeftChannel
isTRUE
,Read()
returns the left channel, ifnChannels == 1
. The following (interleaved little endian) read formats are allowed:SoundFormatUnsigned8
SoundFormatSigned16
SoundFormatSigned24 (occupies 3 bytes)
SoundFormatSigned24_32 (occupies 4 bytes)
-
int CSoundBaseDevice::Read(void *pBuffer, size_t nCount)
Moves up to
nCount
bytes of audio samples intopBuffer
from the input queue and returns the number of returned bytes, which is a multiple of the frame size in any case, or 0 if no data is available.nCount
must be a multiple of the frame size. This method can be called on any CPU core.
-
unsigned CSoundBaseDevice::GetReadQueueSizeFrames(void)
Returns the input queue size in number of frames. This method can be called on any CPU core.
-
unsigned CSoundBaseDevice::GetReadQueueFramesAvail(void)
Returns the number of frames currently available in the input queue, which are waiting to be read by the application. This method can be called on any CPU core.
-
void CSoundBaseDevice::RegisterHaveDataCallback(TSoundDataCallback *pCallback, void *pParam)
Registers the callback function
pCallback
, which is called, when enough sound data is available forRead()
, which means that at least half of the queue is full.pParam
is a user parameter to be handed over to the callback. The callback function has this prototype:TSoundDataCallback()
.
Alternate interface
Optionally an application can bypass the output and/or input queues and can directly provide/consume the audio samples to/from a buffer, which is handed over to the callback methods GetChunk()
and/or PutChunk()
. This/These method(s) have to be overwritten to use the alternate interface. The format of the samples depends on the used hardware/software interface:
Interface |
Format |
Remarks |
---|---|---|
PWM |
SoundFormatUnsigned32 |
range max. depends on sample rate and PWM clock rate |
I2S |
SoundFormatSigned24_32 |
occupies 4 bytes |
HDMI |
SoundFormatIEC958 |
special frame format (S/PDIF) |
VCHIQ |
SoundFormatSigned16 |
occupies 4 bytes |
-
virtual int CSoundBaseDevice::GetRangeMin(void) const
-
virtual int CSoundBaseDevice::GetRangeMax(void) const
Return the minimum/maximum value of one sample. These methods can be called on any CPU core.
-
boolean CSoundBaseDevice::AreChannelsSwapped(void) const
Returns
TRUE
, if the application has to write the right channel first into buffer inGetChunk()
.
-
virtual unsigned CSoundBaseDevice::GetChunk(s16 *pBuffer, unsigned nChunkSize)
-
virtual unsigned CSoundBaseDevice::GetChunk(u32 *pBuffer, unsigned nChunkSize)
You may override one of these methods to provide the sound samples. The first method is used for the VCHIQ interface, the second for all other interfaces.
pBuffer
is a pointer to the buffer, where the samples have to be placed.nChunkSize
is the size of the buffer in words. Returns the number of words written to the buffer, which is normallynChunkSize
, or 0 to stop the transfer. Each sample consists of two words (left channel, right channel), where each word must be betweenGetRangeMin()
andGetRangeMax()
. The HDMI interface requires a special frame format here, which can be applied usingConvertIEC958Sample()
.
-
virtual void CSoundBaseDevice::PutChunk(const u32 *pBuffer, unsigned nChunkSize)
You may override this method to consume the received sound samples.
pBuffer
is a pointer to the buffer, where the samples have been placed.nChunkSize
is the size of the buffer in words. Each sample consists of two words (left channel, right channel).
-
u32 CSoundBaseDevice::ConvertIEC958Sample(u32 nSample, unsigned nFrame)
This method can be called from
GetChunk()
to apply the framing on IEC958 (S/PDIF) samples.nSample
is a 24-bit signed sample value asu32
, where upper bits don’t care.nFrame
is the number of the IEC958 frame, this sample belongs to (0..191).
CPWMSoundBaseDevice
#include <circle/pwmsoundbasedevice.h>
-
class CPWMSoundBaseDevice : public CSoundBaseDevice
This class is a driver for the PWM sound interface. The generated sound is available via the 3.5” headphone jack, provided by most Raspberry Pi models. Most of the methods, available for using this class, are provided by the base class
CSoundBaseDevice
. Only the constructor is specific to this class. This device has the name"sndpwm"
in the device name service (character device).
Note
On the Raspberry Pi Zero, which does not have a headphone jack, the output from the PWM sound interface can be used via the GPIO header. You have to define the system option USE_PWM_AUDIO_ON_ZERO
for this purpose. See the file include/circle/sysconfig.h for details!
-
CPWMSoundBaseDevice::CPWMSoundBaseDevice(CInterruptSystem *pInterrupt, unsigned nSampleRate = 44100, unsigned nChunkSize = 2048)
Constructs an instance of this class. There can be only one.
pInterrupt
is a pointer to the interrupt system object.nSampleRate
is the sample rate in Hz.nChunkSize
is twice the number of samples (words) to be handled with one call toGetChunk()
(one word per stereo channel). Decreasing this value also decreases the latency on this interface, but increases the IRQ load on CPU core 0.
CPWMSoundDevice
#include <circle/pwmsounddevice.h>
-
class CPWMSoundDevice : public CPWMSoundBaseDevice
This class is a PWM playback device for sound data, which is available in main memory. It extents the class
CPWMSoundBaseDevice
, but has its own interface. The sample rate is fixed at 44100 Hz.
-
CPWMSoundDevice::CPWMSoundDevice(CInterruptSystem *pInterrupt)
Constructs an instance of this class. There can be only one.
pInterrupt
is a pointer to the interrupt system object.
-
void CPWMSoundDevice::Playback(void *pSoundData, unsigned nSamples, unsigned nChannels, unsigned nBitsPerSample)
Starts playback of the sound data at
pSoundData
via the PWM sound device.nSamples
is the number of samples, where for Stereo the L/R samples are count as one.nChannels
is 1 for Mono or 2 for Stereo.nBitsPerSample
is 8 (unsigned char sound data) or 16 (signed short sound data).
-
boolean CPWMSoundDevice::PlaybackActive(void) const
Returns
TRUE
, while the playback is active.
-
void CPWMSoundDevice::CancelPlayback(void)
Cancels the playback. The operation takes affect with a short delay, after which
PlaybackActive()
returnsFALSE
.
CI2SSoundBaseDevice
#include <circle/i2ssoundbasedevice.h>
-
class CI2SSoundBaseDevice : public CSoundBaseDevice
This class is a driver for the I2S sound interface. The generated sound is available via the GPIO header in the format: two 32-bit wide channels with 24-bit signed data. Most of the methods, available for using this class, are provided by the base class
CSoundBaseDevice
. Only the constructor is specific to this class. This device has the name"sndi2s"
in the device name service (character device).
Note
The following GPIO pins have to be connected (SoC numbers, not header positions):
Name |
Pin number |
On early models |
Description |
---|---|---|---|
PCM_CLK |
GPIO18 |
GPIO28 |
Bit clock (output or input) |
PCM_FS |
GPIO19 |
GPIO29 |
Frame clock (output or input) |
PCM_DIN |
GPIO20 |
GPIO30 |
Data input (not for TX only mode) |
PCM_DOUT |
GPIO21 |
GPIO31 |
Data output (not for RX only mode) |
The clock pins are outputs in master mode, or inputs in slave mode. On early models the signals are exposed on the separate P5 header.
Note
This driver class supports several I2S interfaces. Some interfaces require an additional I2C connection to work. The following interfaces are known to work:
pHAT DAC (with PCM5102A DAC)
PiFi DAC+ v2.0 (with PCM5122 DAC)
Adafruit I2S Audio Bonnet (with UDA1334A DAC)
Adafruit I2S 3W Class D Amplifier Breakout (with MAX98357A DAC)
-
CI2SSoundBaseDevice::CI2SSoundBaseDevice(CInterruptSystem *pInterrupt, unsigned nSampleRate = 192000, unsigned nChunkSize = 8192, boolean bSlave = FALSE, CI2CMaster *pI2CMaster = 0, u8 ucI2CAddress = 0, TDeviceMode DeviceMode = DeviceModeTXOnly)
Constructs an instance of this class. There can be only one.
pInterrupt
is a pointer to the interrupt system object.nSampleRate
is the sample rate in Hz.nChunkSize
is twice the number of samples (words) to be handled with one call toGetChunk()
(one word per stereo channel). Decreasing this value also decreases the latency on this interface, but increases the IRQ load on CPU core 0.bSlave
enables the slave mode (PCM clock and FS clock are inputs).pI2CMaster
is a pointer to an I2C master object (0 if no I2C DAC initialization is required).ucI2CAddress
is the I2C slave address of the DAC (0 for auto probing the addresses 0x4C and 0x4D).DeviceMode
selects, which transfer direction will be used, with this supported values:DeviceModeTXOnly (output)
DeviceModeRXOnly (input)
DeviceModeTXRX (output and input)
CHDMISoundBaseDevice
#include <circle/hdmisoundbasedevice.h>
-
class CHDMISoundBaseDevice : public CSoundBaseDevice
This class is a driver for HDMI displays with audio support. It directly accesses the hardware and does not require Multitasking support and the VCHIQ driver in the system. Most of the methods, available for using this class, are provided by the base class
CSoundBaseDevice
. This device has the name"sndhdmi"
in the device name service (character device).
Note
This driver does not support HDMI1 on the Raspberry Pi 4 and 400 (HDMI0 only).
This driver supports a DMA and a polling mode. The latter is intended for very time critical and cache-sensitive applications, which cannot use interrupts.
-
CHDMISoundBaseDevice::CHDMISoundBaseDevice(CInterruptSystem *pInterrupt, unsigned nSampleRate = 48000, unsigned nChunkSize = 384 * 10)
Constructs an instance of this class to work in DMA mode. There can be only one.
pInterrupt
is a pointer to the interrupt system object.nSampleRate
is the sample rate in Hz.nChunkSize
is twice the number of samples (words) to be handled with one call toGetChunk()
(one word per stereo channel, must be a multiple of 384). Decreasing this value also decreases the latency on this interface, but increases the IRQ load on CPU core 0.
-
CHDMISoundBaseDevice::CHDMISoundBaseDevice(unsigned nSampleRate = 48000)
Constructs an instance of this class to work in polling mode. There can be only one.
nSampleRate
is the sample rate in Hz.
-
boolean CHDMISoundBaseDevice::IsWritable(void)
Returns if the data FIFO has room for at least one sample to be written? This method can be called in polling mode only.
-
void CHDMISoundBaseDevice::WriteSample(s32 nSample)
Writes one sample to the data FIFO.
nSample
is the 24-bit signed sample to be written. This method can be called in polling mode only and only, whenIsWritable()
returnedTRUE
before. Must be called twice for each frame (for left and right channel).
CVCHIQSoundBaseDevice
#include <vc4/sound/vchiqsoundbasedevice.h>
-
class CVCHIQSoundBaseDevice : public CSoundBaseDevice
This class provides low-level access to the VCHIQ sound service, which is able to output sound via HDMI displays with audio support, or via the 3.5” headphone jack of Raspberry Pi models, which have it. This class requires, that the Multitasking support and the VCHIQ driver are available in the system. Most of the methods, available for using this class, are provided by the base class
CSoundBaseDevice
. This class description covers only the methods, which are specific to this class. This device has the name"sndvchiq"
in the device name service (character device).
-
CVCHIQSoundBaseDevice::CVCHIQSoundBaseDevice(CVCHIQDevice *pVCHIQDevice, unsigned nSampleRate = 44100, unsigned nChunkSize = 4000, TVCHIQSoundDestination Destination = VCHIQSoundDestinationAuto)
Constructs an instance of this class. There can be only one.
pVCHIQDevice
is a pointer to the VCHIQ interface device.nSampleRate
is the sample rate in Hz (44100..48000).nChunkSize
is the number of samples transferred at once.Destination
is the target device, the sound data is sent to (detected automatically, if equal toVCHIQSoundDestinationAuto
), with these possible values:
-
enum TVCHIQSoundDestination
VCHIQSoundDestinationAuto
VCHIQSoundDestinationHeadphones
VCHIQSoundDestinationHDMI
VCHIQSoundDestinationUnknown
-
void CVCHIQSoundBaseDevice::SetControl(int nVolume, TVCHIQSoundDestination Destination = VCHIQSoundDestinationUnknown)
Sets the output volume to
nVolume
(-10000..400) and optionally the target device toDestination
(not modified, if equal toVCHIQSoundDestinationUnknown
). This method can be called, while the sound data transmission is running. The following macros are defined for specifying the volume:
-
VCHIQ_SOUND_VOLUME_MIN
-
VCHIQ_SOUND_VOLUME_DEFAULT
-
VCHIQ_SOUND_VOLUME_MAX
CVCHIQSoundDevice
#include <vc4/sound/vchiqsounddevice.h>
-
class CVCHIQSoundDevice : private CVCHIQSoundBaseDevice
This class is a VCHIQ playback device for sound data, which is available in main memory. It extents the class
CVCHIQSoundBaseDevice
, but has its own interface. The sample rate is fixed at 44100 Hz.
-
CVCHIQSoundDevice::CVCHIQSoundDevice(CVCHIQDevice *pVCHIQDevice, TVCHIQSoundDestination Destination = VCHIQSoundDestinationAuto)
Constructs an instance of this class. There can be only one.
pVCHIQDevice
is a pointer to the VCHIQ interface device.Destination
is the target device, the sound data is sent to (seeTVCHIQSoundDestination
for the available options).
-
boolean CVCHIQSoundDevice::Playback(void *pSoundData, unsigned nSamples, unsigned nChannels, unsigned nBitsPerSample)
Starts playback of the sound data at
pSoundData
via the VCHIQ sound device.nSamples
is the number of samples, where for Stereo the L/R samples are count as one.nChannels
is 1 for Mono or 2 for Stereo.nBitsPerSample
is 8 (unsigned char sound data) or 16 (signed short sound data). ReturnsTRUE
on success.
-
boolean CVCHIQSoundDevice::PlaybackActive(void) const
Returns
TRUE
, while the playback is active.
-
void CVCHIQSoundDevice::CancelPlayback(void)
Cancels the playback. The operation takes affect with a short delay, after which
PlaybackActive()
returnsFALSE
.
-
void CVCHIQSoundDevice::SetControl(int nVolume, TVCHIQSoundDestination Destination = VCHIQSoundDestinationUnknown)
CUSBMIDIDevice
#include <circle/usb/usbmidi.h>
-
class CUSBMIDIDevice : public CUSBFunction
This class is a driver for USB Audio Class MIDI 1.0 devices. An instance of this class is automatically created, when a compatible device is found in the USB device enumeration process. Therefore only the class methods needed to use an USB MIDI device by an application are described here, not the methods used for initialization. This device has the name
"umidiN"
(N >= 1) in the device name service (character device).
Note
See the Universal Serial Bus Device Class Definition for MIDI Devices, Release 1.0 for information about USB MIDI packets and virtual MIDI cables!
-
void CUSBMIDIDevice::RegisterPacketHandler(TMIDIPacketHandler *pPacketHandler)
Registers a callback function, which is called, when a MIDI packet arrives.
pPacketHandler
is a pointer to the function, which has the following prototype:
-
typedef void TMIDIPacketHandler(unsigned nCable, u8 *pPacket, unsigned nLength)
nCable
is the number of the virtual MIDI cable (0..15).pPacket
is a pointer to one received MIDI packet.nLength
is the number of valid bytes in the packet (1..3).
-
boolean CUSBMIDIDevice::SendEventPackets(const u8 *pData, unsigned nLength)
Sends one or more packets in the encoded USB MIDI event packet format.
pData
is a pointer to the packet buffer.nLength
is the length of the packet buffer in bytes, which must be a multiple of 4. ReturnsTRUE
, if the operation has been successful. This function fails, ifnLength
is not a multiple of 4 or the send function is not supported. The format of the USB MIDI event packets is not validated.
-
boolean CUSBMIDIDevice::SendPlainMIDI(unsigned nCable, const u8 *pData, unsigned nLength)
Sends one or more messages in plain MIDI message format.
nCable
is the number of the virtual MIDI cable (0..15).pData
is a pointer to the message buffer.nLength
is the length of the message buffer in bytes. ReturnsTRUE
, if the operation has been successful. This function fails, if the message format is invalid or the send function is not supported.
Network devices
Network devices allow the low-level access to network interfaces, and provide methods for sending and receiving network frames and additional functions to manage the network access. Circle supports the access to IEEE 802.3 Ethernet and to IEEE 802.11 wireless LAN (WLAN) interfaces. All network device classes are derived from the base class CNetDevice
, which defines the low-level API for network applications. Please note, that applications normally use the high-level TCP/IP socket interface, which is provided by the class CSocket
.
CNetDevice
#include <circle/netdevice.h>
-
class CNetDevice
This class is the base class for all network device driver classes and defines the low-level API for specific network applications, which want to directly exchange frames via a network interface. Network devices are not registered in the device name service and can be found using the methods
CNetDevice::GetNetDevice()
.
-
FRAME_BUFFER_SIZE
This macro defines the maximum size of a sent or received frame on a network interface. Network buffers usually have this size in Circle.
-
virtual TNetDeviceType CNetDevice::GetType(void)
Returns the type of this network device, which is one of these:
-
type TNetDeviceType
NetDeviceTypeEthernet
NetDeviceTypeWLAN
-
virtual const CMACAddress *CNetDevice::GetMACAddress(void) const
Returns a pointer to a MAC address object, which holds our own address at this network interface device.
-
virtual boolean CNetDevice::IsSendFrameAdvisable(void)
Returns
TRUE
, if it is advisable to callSendFrame()
.
Note
SendFrame()
can be called at any time, but may fail, when the TX queue is full. This method gives a hint, if calling SendFrame()
is advisable.
-
virtual boolean CNetDevice::SendFrame(const void *pBuffer, unsigned nLength)
Sends a valid frame to the network.
pBuffer
is a pointer to the frame, which does not contain the frame checking sequence (FCS).nLength
is the frame length in bytes. The frame does not need to be padded by the application.
-
virtual boolean CNetDevice::ReceiveFrame(void *pBuffer, unsigned *pResultLength)
Polls for a frame, which has been received via the network interface.
pBuffer
is a pointer to a buffer, where the frame will be placed, and must have the sizeFRAME_BUFFER_SIZE
.pResultLength
is a pointer to a variable, which receives the valid frame length. ReturnsTRUE
, if a frame is returned in the buffer,FALSE
, if nothing has been received.
-
virtual boolean CNetDevice::IsLinkUp(void)
Returns
TRUE
, if the physical link (PHY) is active.
-
virtual TNetDeviceSpeed CNetDevice::GetLinkSpeed(void)
Returns the speed of the physical link (PHY), if it is active, or
NetDeviceSpeedUnknown
, if it is not known. The following link speeds are defined:
-
type TNetDeviceSpeed
NetDeviceSpeed10Half
NetDeviceSpeed10Full
NetDeviceSpeed100Half
NetDeviceSpeed100Full
NetDeviceSpeed1000Half
NetDeviceSpeed1000Full
NetDeviceSpeedUnknown
-
virtual boolean CNetDevice::UpdatePHY(void)
Updates the device settings according to physical link (PHY) status. Returns
FALSE
, if this function is not supported.
Note
This method is called continuously every two seconds by the PHY task of the TCP/IP networking subsystem. If you do not use this subsystem, you have to call this method on your own.
-
static const char *CNetDevice::GetSpeedString(TNetDeviceSpeed Speed)
Returns a description for the link speed value
Speed
, which normally has been returned fromGetLinkSpeed()
.
-
static CNetDevice *CNetDevice::GetNetDevice(unsigned nDeviceNumber)
Returns a pointer to the network device object for the zero-based number
nDeviceNumber
of a network device, or 0, if the device is not available.
-
static CNetDevice *CNetDevice::GetNetDevice(TNetDeviceType Type)
Returns a pointer to the first network device object of the type
Type
, which is either a specific network device type (seeCNetDevice::GetType()
), orNetDeviceTypeAny
to search for any network device.
CSMSC951xDevice
#include <circle/usb/smsc951x.h>
-
class CSMSC951xDevice : public CUSBFunction, CNetDevice
This class is a driver for the SMSC9512 and SMSC9514 Ethernet network interface devices, which are attached to the internal USB hub of Raspberry Pi 1, 2 and 3 Model B boards. This class is automatically instantiated in the USB device enumeration process, when a device of this type is found. This class does not provide specific methods, its API is defined by the base class
CNetDevice
.
CLAN7800Device
#include <circle/usb/lan7800.h>
-
class CLAN7800Device : public CUSBFunction, CNetDevice
This class is a driver for the LAN7800 Gigabit Ethernet network interface device, which is attached to an internal USB hub of the Raspberry Pi 3 Model B+ board. This class is automatically instantiated in the USB device enumeration process, when a device of this type is found. This class does not provide specific methods, its API is defined by the base class
CNetDevice
.
CUSBCDCEthernetDevice
#include <circle/usb/usbcdcethernet.h>
-
class CUSBCDCEthernetDevice : public CUSBFunction, CNetDevice
This class is a driver for the USB CDC Ethernet network interface device, which is supported by QEMU. This class is automatically instantiated in the USB device enumeration process, when a device of this type is found. This class does not provide specific methods, its API is defined by the base class
CNetDevice
.
CBcm54213Device
#include <circle/bcm54213.h>
-
class CBcm54213Device : public CNetDevice
This class is a driver for the BCM54213PE Gigabit Ethernet Transceivers of the Raspberry Pi 4, 400 and Compute Module 4. It is instantiated in the TCP/IP networking subsystem, but has to be manually instantiated by applications, which do not use this subsystem. This class does not provide specific methods, its API is defined by the base class
CNetDevice
.
CBcm4343Device
#include <wlan/bcm4343.h>
-
class CBcm4343Device : public CNetDevice
This class is a driver for the BCM4343x WLAN interface device of the Raspberry Pi 3, 4 and Zero (2) W. It has to be instantiated manually, and is normally used together with the class
CNetSubSystem
from the TCP/IP networking subsystem and the classCWPASupplicant
from the submodule hostap. This class provides the interface, defined in its base classCNetDevice
, and additional methods, which are needed to manage the association with a WLAN access point (AP). The following description covers only the methods, which are specific to this class.
-
CBcm4343Device::CBcm4343Device(const char *pFirmwarePath)
Creates an instance of this class.
pFirmwarePath
points to the path, where the firmware files for the WLAN controller are provided (e.g. “SD:/firmware/”).
-
boolean CBcm4343Device::Initialize(void)
Initializes the WLAN controller and driver. Returns
TRUE
on success.
-
void CBcm4343Device::RegisterEventHandler(TBcm4343EventHandler *pHandler, void *pContext)
Registers the event handler
pHandler
, which is called on some specific WLAN events (e.g. disassociation from AP).pContext
is a user pointer, which is handed over to the event handler.pHandler
can be 0 to unregister the event handler.
-
boolean CBcm4343Device::Control(const char *pFormat, ...)
Sends the device specific control command
pFormat
with optional parameters to the WLAN device driver. ReturnsTRUE
on success.
-
boolean CBcm4343Device::ReceiveScanResult(void *pBuffer, unsigned *pResultLength)
Polls for a received scan result message.
pBuffer
is a pointer to a buffer, where the message will be placed. The buffer must have the sizeFRAME_BUFFER_SIZE
.pResultLength
is a pointer to a variable, which receives the valid message length. ReturnsTRUE
, if a message is returned in the buffer, orFALSE
if nothing has been received.
-
const CMACAddress *CBcm4343Device::GetBSSID(void)
Returns the BSSID of the associated AP.
-
boolean CBcm4343Device::JoinOpenNet(const char *pSSID)
Joins the open WLAN network with the SSID
pSSID
. ReturnsTRUE
on success.
-
boolean CBcm4343Device::CreateOpenNet(const char *pSSID, int nChannel, bool bHidden)
Creates an open WLAN network (AP mode) with the SSID
pSSID
on channelnChannel
. The SSID is hidden, ifbHidden
isTRUE
. ReturnsTRUE
on success.
Other devices
This section covers some device driver classes, which do not belong to other groups of devices. These classes have their own interface and are not derived from the class CDevice
.
CBcmFrameBuffer
#include <circle/bcmframebuffer.h>
-
class CBcmFrameBuffer
This class is a driver for the frame buffer device(s), provided by the firmware of the Raspberry Pi. The Raspberry Pi 4, 400 and the Compute Module 4 support multiple frame buffer devices, all other models only one. A frame buffer is basically an address range in main memory, which is continuously read by the firmware in background, to be displayed on a HDMI or composite TV display. Writing to this memory address range modifies the displayed image. The Raspberry Pi firmware supports frame buffers with different widths, heights and depths of the pixel information. If one wants to display text in a frame buffer, the characters must be formed from a character generator in the software. The firmware does not support text displays on its own.
Note
To be able to use more than one frame buffer device, the option max_framebuffers=N
(N > 1) is required in the file config.txt on the SD card.
-
CBcmFrameBuffer::CBcmFrameBuffer(unsigned nWidth, unsigned nHeight, unsigned nDepth, unsigned nVirtualWidth = 0, unsigned nVirtualHeight = 0, unsigned nDisplay = 0, boolean bDoubleBuffered = FALSE)
Constructs a frame buffer device object with
nWidth
*nHeight
pixels. If both parameters are zero, the frame buffer is automatically created with the default size, which is normally the maximum supported size of the connected display. Each pixel has a depth ofnDepth
bits (4, 8, 16, 24 or 32).The memory range of the frame buffer may be larger than the displayed physical display size. This can be used to quickly switch the displayed image (see
SetVirtualOffset()
). The optional virtual display size isnVirtualWidth
*nVirtualHeight
pixels. IfbDoubleBuffered
isTRUE
, the virtual display height is automatically set to twice the physical display size, ifnVirtualWidth
andnVirtualHeight
are specified as 0.nDisplay
is the zero-based ID number of the frame buffer device, which is transferred to the firmware to select a specific display on the Raspberry Pi 4, 400 and the Compute Module 4.
-
void CBcmFrameBuffer::SetPalette(u8 nIndex, u16 nRGB565)
-
void CBcmFrameBuffer::SetPalette32(u8 nIndex, u32 nRGBA)
Set the entry
nIndex
of the color palette tonRGB565
ornRGBA
. The color palette is only used in in 4-bit or 8-bit pixel depth mode. The color palette must be set beforeInitialize()
is called, but can be updated later.
-
PALETTE_ENTRIES
The maximum number of entries in the color palette in 4-bit or 8-bit depth mode (256).
nIndex
must be below this.
-
boolean CBcmFrameBuffer::Initialize(void)
Initializes the frame buffer device and starts the display. Returns
TRUE
on success.
Note
This method does succeed on Raspberry Pi 1-3 and Zero, even when there is no display connected. On the Raspberry Pi 4, 400 and Compute Module 4 this method fails in this case.
-
u32 CBcmFrameBuffer::GetWidth(void) const
-
u32 CBcmFrameBuffer::GetHeight(void) const
-
u32 CBcmFrameBuffer::GetVirtWidth(void) const
-
u32 CBcmFrameBuffer::GetVirtHeight(void) const
Return the physical or virtual size of the frame buffer in number of pixels.
-
u32 CBcmFrameBuffer::GetPitch(void) const
Returns the size of one pixel line in memory in number of bytes and may contain padding bytes.
-
u32 CBcmFrameBuffer::GetDepth(void) const
Returns the size of one pixel in memory in number of bits.
-
u32 CBcmFrameBuffer::GetBuffer(void) const
-
u32 CBcmFrameBuffer::GetSize(void) const
Return the address and total size of the frame buffer in main memory.
-
boolean CBcmFrameBuffer::UpdatePalette(void)
Updates the color palette, after modifying it using
SetPalette()
orSetPalette32()
. ReturnsTRUE
on success. This method should be used only with a pixel depth of 4 or 8 bits.
-
boolean CBcmFrameBuffer::SetVirtualOffset(u32 nOffsetX, u32 nOffsetY)
Sets the offset of the top-left corner of the physically displayed image in a larger virtual frame buffer to [
nOffsetX
,nOffsetY
]. ReturnsTRUE
on success.
-
boolean CBcmFrameBuffer::WaitForVerticalSync(void)
Waits for the next vertical synchronization (VSYNC) blanking gap. Returns
TRUE
on success.
-
boolean CBcmFrameBuffer::SetBacklightBrightness(unsigned nBrightness)
Sets the backlight brightness level of the display to
nBrightness
. This has been tested with the Official 7” Raspberry Pi touchscreen only. The brightness level can be about 0..180 there. ReturnsTRUE
on success.
-
static unsigned CBcmFrameBuffer::GetNumDisplays(void)
Returns to number of available displays, which is always 1 on models other than the Raspberry Pi 4, 400 or Compute Module 4.
CBcmRandomNumberGenerator
#include <circle/bcmrandom.h>
-
class CBcmRandomNumberGenerator
This class is a driver for the built-in hardware random number generator.
-
u32 CBcmRandomNumberGenerator::GetNumber(void)
Returns a 32-bit random number.
Note
Generating a random number takes a short while. For generating a large number of random numbers, you should use a polynomial random number generator, and seed it using this hardware random number generator.
CBcmWatchdog
#include <circle/bcmwatchdog.h>
-
class CBcmWatchdog
This class is a driver for the built-in watchdog device. It can be used to automatically restart a Raspberry Pi computer after program failure, or to restart it immediately from a specific partition.
-
void CBcmWatchdog::Start(unsigned nTimeoutSeconds = MaxTimeoutSeconds)
Starts the watchdog, to elapse after
nTimeoutSeconds
seconds. The system restarts after this timeout, if the watchdog is not re-triggered before.
-
const unsigned CBcmWatchdog::MaxTimeoutSeconds = 15
Is the maximum timeout in seconds.
-
void CBcmWatchdog::Stop(void)
Stops the watchdog. It will not elapse any more.
-
void CBcmWatchdog::Restart(unsigned nPartition = PartitionDefault)
Immediately restarts the system from the SD card partition with the number
nPartition
, with these special values:
-
const unsigned CBcmWatchdog::PartitionDefault = 0
-
const unsigned CBcmWatchdog::PartitionHalt = 63
PartitionHalt
halts the system, instead of restarting it.
-
boolean CBcmWatchdog::IsRunning(void) const
Returns
TRUE
, if the watchdog is currently running.
-
unsigned CBcmWatchdog::GetTimeLeft(void) const
Returns the number of seconds left, until a restart will triggered.
Appendices
Libraries
This appendix lists the libraries, which are provided by the Circle project.
Base libraries
The base libraries will be built using ./makeall
from Circle’s project root.
Library lib/… |
Description |
Depends on lib |
---|---|---|
libcircle.a |
Basic system services and drivers |
|
usb/libusb.a |
USB host controller and class drivers |
circle, input, fs |
input/libinput.a |
Generic input device services |
circle |
fs/libfs.a |
Basic file system services (partition manager) |
circle |
fs/fat/libfatfs.a |
FAT file system driver 1 |
circle, fs |
sched/libsched.a |
Cooperative multi-tasking support |
circle |
net/libnet.a |
TCP/IP networking |
circle, sched |
Add-on libraries
Add-on libraries will be built using make
from the target directory. This appendix lists only a subset of the available add-on libraries. All provided add-on modules are listed here.
Library addon/… |
Description |
---|---|
SDCard/libsdcard.a |
EMMC and SDHOST SD card drivers |
fatfs/libfatfs.a |
|
Properties/libproperties.a |
Property file (.ini) support |
linux/liblinuxemu.a |
Linux kernel driver and pthread emulation |
vc4/vchiq/libvchiq.a |
VCHIQ interface driver |
vc4/sound/libvchiqsound.a |
VCHIQ (HDMI) sound driver |
ugui/libugui.a |
|
lvgl/liblvgl.a |
These libraries provide accelerated graphics support for the Raspberry Pi 1-3 and Zero (32-bit only) in addon/vc4/interface/:
bcm_host/libbcm_host.a
khronos/libkhrn_client.a
vmcs_host/libvmcs_host.a
vcos/libvcos.a
Footnotes
System data types
This appendix lists the system data types, which are defined and used by Circle. You can also include <stdint.h>
to use POSIX types. This file is provided by the toolchain and is not available, if your application is built with STDLIB_SUPPORT = 0
.
#include <circle/types.h>
Type |
Description |
---|---|
u8 |
8-bit unsigned value |
u16 |
16-bit unsigned value |
u32 |
32-bit unsigned value |
u64 |
64-bit unsigned value |
s8 |
8-bit signed value |
s16 |
16-bit signed value |
s32 |
32-bit signed value |
s64 |
64-bit signed value |
uintptr |
unsigned value with the size of a pointer |
intptr |
signed value with the size of a pointer |
size_t |
count of bytes, result of the |
ssize_t |
count of bytes or an error value |
boolean |
can be TRUE or FALSE |
Note
boolean
is a synonym for the standard type bool
, which can be used instead, with the values true
or false
. The definition of boolean
has historical reasons, but is still used for an uniform source code.
Macros
This appendix lists the C-macros, which are defined globally by the Circle build system and which can be used in applications for conditional compiling:
Macro |
Description |
---|---|
__circle__ |
Circle version number (e.g. 440400 for Circle 44.4, patch level 0) |
AARCH |
ARM architecture (32 or 64) |
RASPPI |
Major Raspberry Pi model version (1, 2, 3 or 4) |
STDLIB_SUPPORT |
Standard library support level 1 (0, 1, 2 or 3) |
NDEBUG |
Not defined in checked builds (default) |
Footnotes
Analyzing exceptions
This appendix explains, how system abort exceptions can be analyzed. The output from the program in section A more complex program is used for this purpose. It looks like this:
logger: Circle 44.3 started on Raspberry Pi Zero W
00:00:01.00 timer: SpeedFactor is 1.00
00:00:01.00 kernel: An exception will occur after 15 seconds from now
00:00:02.00 kernel: Time is 2
00:00:03.00 kernel: Time is 3
00:00:04.00 kernel: Time is 4
...
00:00:14.00 kernel: Time is 14
00:00:15.00 kernel: Time is 15
00:00:16.00 except: stack[7] is 0xEFBC
00:00:16.00 except: stack[8] is 0xF04C
00:00:16.00 except: stack[11] is 0x11304
00:00:16.00 except: stack[13] is 0x113C4
00:00:16.00 except: stack[23] is 0x11408
00:00:16.00 except: stack[25] is 0x108E4
00:00:16.00 except: stack[31] is 0xE834
00:00:16.00 except: Prefetch abort (PC 0x500000, FSR 0xD, FAR 0x500000,
SP 0x237F80, LR 0xEE7C, PSR 0x20000192)
If you want to detect the instruction, which caused the exception, you can open the file kernel*.lst and search for the address in PC (Program Counter). Because this is an invalid address outside the kernel image, you will not find it here, but LR (Link Register) specifies the address, from where TimerHandler()
had been called (0xEE7C). The respective address is located at the beginning of a line in kernel*.lst with a trailing colon:
0000edd0 <CTimer::PollKernelTimers()>:
edd0: e92d41f0 push {r4, r5, r6, r7, r8, lr}
...
ee64: e3530000 cmp r3, #0
ee68: 0a000011 beq eeb4 <CTimer::PollKernelTimers()+0xe4>
ee6c: e1a00004 mov r0, r4
ee70: e5942010 ldr r2, [r4, #16]
ee74: e594100c ldr r1, [r4, #12]
ee78: e12fff33 blx r3
==> ee7c: e1a00004 mov r0, r4
ee80: e3a01014 mov r1, #20
...
Thus TimerHandler()
had been called by the instruction “blx r3”, the preceeding instruction of the given address.
The several listed addresses from the stack[] allow to do a backtrace, but not every shown address needs to be valid. Just search for the addresses in the kernel*.lst file, starting with the first one, and you will get the information, which function has been called from which other function (inside-out).
Note
Raspberry Pi is a trademark of Raspberry Pi Trading.