Quick Introduction to AlfaSat (UniSat) Communication Protocol (ACP(UCP))

 

Orion's Arm - Encyclopedia Galactica - Fiarro Twin Worlds, The

Today We are going to talk about K36/K37, the planet(s) where I came from. You maybe fonfused, why am I talking about the planets on an article of which the title is about something called “Protocol”, I believe you are confusing, yes, that is what humans always do.

The post here assumes that AlfaSat and UniSat is a joint of each, as a single or completly same device except parts of hardware design.

Technichal Terms

AlfaSat

AlfaSat Hardware

AlfaSat (or UniSat) is a nano-satellite which consists from several main hardware parts, including the TOP BOARD, EPS BOARD, OBC BOARD, SENSOR BOARD (AlfaSense), TRX BOARD, ANTENNA BOARD, as shown in the diagram below:

Блок схема системы (1)

The communication internally and externally with the satellite is estabilished on a common rule, as called, AlfaSat Protocol, Physically that is a RS485 Serial Communication Bus.

This post will not focus on boards except OBC and the Sensorboard, as they are the dominant source for the data, other boards follows the same rule and should work very similarly.

The On Board Computer (OBC)

On board computer (OBC) is the major brain of the satellite, responsible for all core functions, like collecting the system data, logging, error handling, data monitoring, and etc.

Here we have two cameras on OBC, one as a general RPi camera that responsible for capturing beautiful space images while the other is responsible for video recordings.

The capturing task (both imaging and video recording) is a software designed task that runs among almost all the satellite life time in a cycled period.

Блок схема платы - OBC

OBC Actions :

  • Listening : standby and listen for the messages.
  • Parsing : Parsing the message, check the source and larget of the message, set the message flag as CALL or FALL.
    • CALL requires further actions to be done (except logging ), espacially messages send to the OBC itself.
    • FALL messages that send to other board, OBC dose not have to take any action, but have to record the message in to the ANGIME.AZT file(as a part of the logging process).
  • Reaction:
    • CALL :
      • (ASYNC) SHOOT : capture image and save the image data & write shooting history to the SHOOT.AZT file. (Target: Data/shoot/2020-09-03-11-23-42.png)
      • (ASYNC) FRAME : record short videos for VAR seconds & write recording history to the FRAME.AZT file. (Target: Data/frame/2020-09-03-11-23-42.mp4)
    • FALL :
      • ANGIME all message history (APPEND)
      • SHOOT all successful capture history (APPEND)
      • FRAME all successful video recording history (APPEND)
      • TOUCH each VAR minute sensorboard (and maybe also from other board data) DATA and it’s history (APPEND)
      • PROCESS system process history
      • LOG system crash and errors.
  • QUERY: Ask data from other board.
  • RESPOND: SEND required data to the BUS.
  • MAMA : SYSTEM LEVEL CRASH. MAY BE UN RECOVERABLE
  • CHECK : SYSTEM TEMP, SYSTEM MEM, SYSTEM STORAGE.

TODO : FURTHER DEFINITIONS AND CONCRETE EXPLANATIONS AND SAMPLE”S REQUIRED>.

The Sensor Board

As it’s obvious by the name, Sensorboard is the part which responsible for reading and writing (or responding) sensor data.

AlfaSense Consept B-Page-1 (1)

Sensorboard should work properly during the ascending and the decending process.

CMD2

The Sensorboard Actions:

  • Listening : standby and listen for the messages.
  • Parsing : Parsing the message, check the source and larget of the message, set the message flag as LOVE or POKE.
    • LOVE requires response. And should return some data to the outside. (GET OR SET)
    • POKE message is not send for the Sensorboard and can be ignored.
  • Reaction:
    • GET:
      • GET from cache array
      • GET from REAL-TIME
    • SET : set global variables
  • RESPOND: SEND required data to the BUS.

The Satellite Life Cycle

alfasat-lifetime

The satellite life cycle is very important for structuring the software code by period and testing. As is mensioned, Sensor Board and OBC has major functions during the life cycle.

Digital Data

Digital data is a natural choice for communications. The smallest unit of digital data is a Bit, or binary digit, and it has just two states: Off, represented by a 0; and On, represented by a 1. Since the 1960s, most computerized devices have relied on miniaturized, two-state transistors that are either off or on. And a voltage associated with the transistor is either low (0) or high (1). A bit’s value is represented using base 2, and can only be 0 or 1. Digital data can be generated and transmitted very quickly by electronic equipment.

PNP Transistor Circuit Characteristics, Working, Applications

Almost all transmitted data is at least one byte long. A byte consists of 8 consecutive bits, or binary digits. A byte can have up to 256 (28 ) values. In reality, data is frequently communicated in 2, 4 or 8 byte units. A data unit with 2 bytes (16 bits) is often called a Word.

Keshav's Blog: Bit vs Byte

The TCP/IP Guide - Binary Information and Representation: Bits, Bytes,  Nibbles, Octets and Characters

Measurements that mean something in the real world - levels, pressures, temperatures, etc. - can easily be represented with 2 or 4 bytes. So can the ranges of set points. Likewise the On or Off state of a device like a motor. Within computers and microprocessors, arithmetic operations on data that has a digital equivalent is readily done. They can easily manipulate data in binary, or base 2.

Before microprocessor-based controllers became the dominant control technology in the early 1980s, controllers for applications like refineries, chemical plants, and power plants mostly used analog electronic control systems.

Analog signals vary in a range. These analog systems had some serious limitations. One was that analog signals were susceptible to being corrupted by electrical noise and unintentional grounds. Another was that settings and calculated values in control loops tended to drift over time, especially as components heated up.

Difference Between Analog and Digital Signal (with Comparison Chart) - Tech  Differences

Digital data communications through protocols has the advantages that it is inherently more stable, reliable, and less susceptible to electrical noise than analog signals.

Another advantage of digital communications is that a lot of data can be communicated on a single network or fieldbus cable. This reduces end users’ needs for installing controller input and output modules, wiring, conduit, etc. It also lets users connect different types of devices to the same communications cable, such as transmitters and actuators. And it also makes it easier find the sources of problem conditions readily.

Fieldbus is defined as “a family of industrial computer network protocols used for realtime distributed control, standardized as IEC 61158.”

FOUNDATION fieldbus - Alchetron, The Free Social Encyclopedia

Worldwide, plants are continuing to use sensors, transmitters and actuators that transmit or respond to analog signals. Controllers handle that by embedding Analog-to-Digital (A/D) and Digital-toAnalog (D/A) converters in input and output modules. For example, most incoming analog signals are converted from a voltage1 to a 16-bit integer within a controller. That makes it easy for a controller to use the data.

Binary

Hexadecimal

ASCII

Network, Nodes, and Topologies

A Network is an interconnected group of computers and/or controllers, and devices that interact with computers and controllers. A Node is a computer or other device in a network. Networks are interconnected by different types of conversion devices, cables, and sometimes, by radio transceivers.

Network Diagram Templates & Network Diagram Examples at Creately

3 common topologies, or arrangements for networks, are discussed below:

  • BUS
  • STAR
  • Ring
graph LR
networks --> Bus & Star & Ring

The Bus topology is the simplest.

image-20200903154311152

Note the presence of resistors at the ends of the bus. Each node is exposed to data traffic on the bus, but it will only respond if data is directed to it. Otherwise the data is ignored. A bus topology has the disadvantage that failure of the bus cable will stop communications. End resistors with identical resistances are used to improve signal quality on the bus.

AlfaSat (UniSat ) Uses a RS 485 Modbus RTU Network.

A Point-to-Point connection is the simplest example of the bus topology. Point-to-point connections are used, for example, to connect a PC and a single printer.

Star topology:

image-20200903154538115

In a Star topology (Figure 1B), individual nodes are connected to a central node. In a Star topology (Figure 1B), individual nodes are connected to a central node. Very often the central node is a Switch. Switches allow temporary pathways to be made so any node on the network can communicate with any other node. In a star topology, an individual node can be disconnected without affecting communications on the rest of the network. It’s more reliable than a bus topology. All data traffic stops if the central node fails. However, switches are built for high reliability, and often, Uninterruptible Power Supplies are connected to provide temporary backup power in event of loss of line power. Sometimes redundant switches are used for improved reliability. In that case, each node has two ports, with separate cables attached to each distributed node.

Ring Topology:

image-20200903154658683

Figure 1C on page 9 illustrates the Ring topology. The ring doesn’t have a master device. Each node can both send and transmit data. Data sent from one node to another is forwarded around the ring from the originating node to the destination node to which it is addressed. If a segment fails, data can be sent in the reverse direction.

Many different types of devices besides computers, controllers and switches can be can be part of a network – such as printers, scanners, barcode readers, TV camera, etc.

In reality, networks are interconnected in many different ways. Some networks consist of combinations of one or more of the three basic networks. In a properly set-up network, data can get from one node to another as long as a path for data transmission exists.

Most networks have a central computer known as a Server. Servers are computers which meet higher standards for dependability, durability, and speed of access to data than ordinary desktop computers. Typically they also have far larger data storage capacity. Servers are frequently set up in redundant pairs. Computers in a network which act only as “dumb terminals” - which operators can use for monitoring and control, but don’t directly interact with controllers or perform processing tasks - are referred to as Clients. A server processes requests from its clients and interacts with controllers. Servers are often referred to as Thick Clients, and client PCs are sometimes called Thin Clients. Such networks are usually called Client-Server Networks.

Many plants and facilities have multiple client PCs and controllers in various locations. So use of servers in process control applications is sensible for 4 reasons: first, to centralize key databases used to monitor the site in one reliable computer (or redundant pair of computers). Second, historical data can be stored on servers. Third, use of servers simplifies access to shared resources such as printers. Last, a Client-Server network allows appropriate delegation of roles and tasks to different entities.

And client operator terminals that are networked with a server can access the server’s database(s) for several purposes:

  • To allow operators to monitor operations at a plant’s subsystems.
  • To let operators start and stop equipment as needed, and adjust set points for automatic control.
  • To view alarm screens
  • To access trend screens which show how key levels, pressures, temperatures, etc., have varied over time.
  • To view accumulated values such as total flow in a day, and numbers of equipment starts.
  • To view archived data.

Some communication cables have one group of conductors or fibers for communication in one direction, and another group of conductors or fibers for communication in the other direction.

Regarding such cables, two communications terms sometimes used are Half-duplex and Full-duplex. Half-duplex refers to the transmission of data in only one direction at a time on a cable or other data link. Full-duplex refers to the transmission of data in two directions simultaneously. Typical copper Ethernet cable has separate pairs of conductors for data transfer in opposite directions.

Simplex vs. Duplex Fibre

The OSI Model and its importance

The OSI, or Open Systems Interconnect model, is the next topic. The OSI model is a theoretical model of how communications occur on a network. It has 7 layers. It’s helpful to refer to the OSI model to explain features of protocols, hardware and networks. The layers are:

![The OSI Model. OSI, stands for Open Systems… by Derya Cortuk Medium](https://azatai.s3.amazonaws.com/static/100514.png)
  • Layer 1 (Physical): This layer considers only the physical aspects of a network; the cables, converters, interconnecting devices, etc.
  • Layer 2 (Data-link): This layer concerns itself with how Layers 1 and 3 work together.
  • Layer 3 (Network): This layer provides an addressing scheme for routing of data and messages.
  • Layer 4 (Transport): This layer makes sure that messages get to their correct destination.
  • Layer 5 (Session): This layer handles the actual connections between systems.
  • Layer 6 (Presentation): This layer deals with the way different systems represent data.
  • Layer 7 (Application): This layer concerns itself chiefly with the software applications used on a computer screen.
![TCP/IP vs. OSI: What’s the Difference Between the Two Models? FS Community](https://azatai.s3.amazonaws.com/static/100710.png)

Use of protocols involves both software and hardware, and it’s hard, but sometimes necessary, to differentiate between functions performed by hardware devices, and functions performed by software. So it’s helpful to refer to the OSI model sometimes.

OSI model for PLC communications

Protocol

A protocol is a standard set of rules that allow electronic devices to communicate with each other. These rules include what type of data may be transmitted, what commands are used to send and receive data, and how data transfers are confirmed.

Three elements of protocol :

graph LR
A["protocol"] -->B & C & D
B["type"]
C["command"]
D["check"]

You can think of a protocol as a spoken language. Each language has its own rules(grammar) and vocabulary. If two people share the same language, they can communicate effectively.

A protocol is a set of rules for communication among networked devices. Some common protocols used in the industrial arena include:

  • Modbus RTU
  • EtherNet/IP
  • Ethernet TCP/IP
  • Modbus TCP/IP
  • Profinet

Industrial Protocols are vary as below:

image-20200903161541093

Serial & Parallel Communication

Embedded electronics is all about interlinking circuits (processors or other integrated circuits) to create a symbiotic system. In order for those individual circuits to swap their information, they must share a common communication protocol. Hundreds of communication protocols have been defined to achieve this data exchange, and, in general, each can be separated into one of two categories: parallel or serial.

Embedded system - Wikipedia

interlink:

Analog audio interlinks: does quality matter?

Parallel vs. Serial

Parallel interfaces transfer multiple bits at the same time. They usually require buses of data - transmitting across eight, sixteen, or more wires. Data is transferred in huge, crashing waves of 1’s and 0’s.

Parallel Generalization

. An 8-bit data bus, controlled by a clock, transmitting a byte every clock pulse. 9 wires are used.

Serial interfaces stream their data, one single bit at a time. These interfaces can operate on as little as one wire, usually never more than four.

Serial Generalization

Example of a serial interface, transmitting one bit every clock pulse. Just 2 wires required!

Think of the two interfaces as a stream of cars: a parallel interface would be the 8+ lane mega-highway, while a serial interface is more like a two-lane rural country road. Over a set amount of time, the mega-highway potentially gets more people to their destinations, but that rural two-laner serves its purpose and costs a fraction of the funds to build.

Parallel communication certainly has its benefits. It’s fast, straightforward, and relatively easy to implement. But it requires many more input/output (I/O) lines. If you’ve ever had to move a project from a basic Arduino Uno to a Mega, you know that the I/O lines on a microprocessor can be precious and few. So, we often opt for serial communication, sacrificing potential speed for pin real estate.

What is Serial & Parallel?

What is Serial & Parallel?

Asynchronous Serial

Over the years, dozens of serial protocols have been crafted to meet particular needs of embedded systems. USB (universal serial bus), and Ethernet, are a couple of the more well-known computing serial interfaces. Other very common serial interfaces include SPI, I2C, and others.

Each of these serial interfaces can be sorted into one of two groups: synchronous or asynchronous.

Difference Between Synchronous and Asynchronous Messaging? – PeopleSoft  Tutorial

A synchronous serial interface always pairs its data line(s) with a clock signal, so all devices on a synchronous serial bus share a common clock. This makes for a more straightforward, often faster serial transfer, but it also requires at least one extra wire between communicating devices. Examples of synchronous interfaces include SPI, and I2C.

![Imagem : Jaxcoder.com GIF Gfycat](https://azatai.s3.amazonaws.com/static/104803.gif)

I2C Communication—Wolfram Language Documentation

Asynchronous means that data is transferred without support from an external clock signal. This transmission method is perfect for minimizing the required wires and I/O pins, but it does mean we need to put some extra effort into reliably transferring and receiving data.

e serial protocol we’ll be discussing in this tutorial is the most common form of asynchronous transfers. It is so common, in fact, that when most folks say “serial” they’re talking about this protocol.

Rules of Serial

The asynchronous serial protocol has a number of built-in rules - mechanisms that help ensure robust and error-free data transfers. These mechanisms, which we get for eschewing the external clock signal, are:

  • Data bits,
  • Synchronization bits,
  • Parity bits,
  • and Baud rate.

[webp-to-png output image]

946cb27d-e06b-4b6b-ae53-17186535b41f

Through the variety of these signaling mechanisms, you’ll find that there’s no one way to send data serially. The protocol is highly configurable. The critical part is making sure that both devices on a serial bus are configured to use the exact same protocols.

Baud Rate

The baud rate specifies how fast data is sent over a serial line. It’s usually expressed in units of bits-per-second (bps). If you invert the baud rate, you can find out just how long it takes to transmit a single bit. This value determines how long the transmitter holds a serial line high/low or at what period the receiving device samples its line.

Baud rates can be just about any value within reason. The only requirement is that both devices operate at the same rate. One of the more common baud rates, especially for simple stuff where speed isn’t critical, is 9600 bps. Other “standard” baud are 1200, 2400, 4800, 19200, 38400, 57600, and 115200.

The higher a baud rate goes, the faster data is sent/received, but there are limits to how fast data can be transferred. You usually won’t see speeds exceeding 115200 - that’s fast for most microcontrollers. Get too high, and you’ll begin to see errors on the receiving end, as clocks and sampling periods just can’t keep up.

Framing the Data

Each block (usually a byte) of data transmitted is actually sent in a packet or frame of bits. Frames are created by appending synchronization and parity bits to our data.

Serial Packet

A serial frame. Some symbols in the frame have configurable bit sizes.

Let’s get into the details of each of these frame pieces.

Data chunk

The real meat of every serial packet is the data it carries. We ambiguously call this block of data a chunk, because its size isn’t specifically stated. The amount of data in each packet can be set to anything from 5 to 9 bits. Certainly, the standard data size is your basic 8-bit byte, but other sizes have their uses. A 7-bit data chunk can be more efficient than 8, especially if you’re just transferring 7-bit ASCII characters.

SCTP DATA chunk / Iptables Tutorial 1.2.2 / Библиотека (книги, учебники и  журналы) / В помощь Веб-Мастеру

After agreeing on a character-length, both serial devices also have to agree on the endianness of their data. Is data sent most-significant bit (msb) to least, or vice-versa? If it’s not otherwise stated, you can usually assume that data is transferred least-significant bit (lsb) first.

Synchronization bits

The synchronization bits are two or three special bits transferred with each chunk of data. They are the start bit and the stop bit(s). True to their name, these bits mark the beginning and end of a packet. There’s always only one start bit, but the number of stop bits is configurable to either one or two (though it’s commonly left at one).

The start bit is always indicated by an idle data line going from 1 to 0, while the stop bit(s) will transition back to the idle state by holding the line at 1.

Parity bits

Parity is a form of very simple, low-level error checking. It comes in two flavors: odd or even. To produce the parity bit, all 5-9 bits of the data byte are added up, and the evenness of the sum decides whether the bit is set or not. For example, assuming parity is set to even and was being added to a data byte like 0b01011101, which has an odd number of 1’s (5), the parity bit would be set to 1. Conversely, if the parity mode was set to odd, the parity bit would be 0.

Parity is optional, and not very widely used. It can be helpful for transmitting across noisy mediums, but it’ll also slow down your data transfer a bit and requires both sender and receiver to implement error-handling (usually, received data that fails must be re-sent).

9600 8N1 (an example)

9600 8N1 - 9600 baud, 8 data bits, no parity, and 1 stop bit - is one of the more commonly used serial protocols. So, what would a packet or two of 9600 8N1 data look like? Let’s have an example!

A device transmitting the ASCII characters ‘O’ and ‘K’ would have to create two packets of data. The ASCII value of O (that’s uppercase) is 79, which breaks down into an 8-bit binary value of 01001111, while K’s binary value is 01001011. All that’s left is appending sync bits.

It isn’t specifically stated, but it’s assumed that data is transferred least-significant bit first. Notice how each of the two bytes is sent as it reads from right-to-left.

"OK" Packet

Since we’re transferring at 9600 bps, the time spent holding each of those bits high or low is 1/(9600 bps) or 104 µs per bit.

For every byte of data transmitted, there are actually 10 bits being sent: a start bit, 8 data bits, and a stop bit. So, at 9600 bps, we’re actually sending 9600 bits per second or 960 (9600/10) bytes per second.

UART

UART stands for Universal Asynchronous Receiver/Transmitter. It’s not a communication protocol like SPI and I2C, but a physical circuit in a microcontroller, or a stand-alone IC. A UART’s main purpose is to transmit and receive serial data.

Basics of UART Communication

In UART communication, two UARTs communicate directly with each other. The transmitting UART converts parallel data from a controlling device like a CPU into serial form, transmits it in serial to the receiving UART, which then converts the serial data back into parallel data for the receiving device. Only two wires are needed to transmit data between two UARTs. Data flows from the Tx pin of the transmitting UART to the Rx pin of the receiving UART:

Introduction to UART - Basic Connection Diagram

UARTs transmit data asynchronously, which means there is no clock signal to synchronize the output of bits from the transmitting UART to the sampling of bits by the receiving UART. Instead of a clock signal, the transmitting UART adds start and stop bits to the data packet being transferred. These bits define the beginning and end of the data packet so the receiving UART knows when to start reading the bits.

When the receiving UART detects a start bit, it starts to read the incoming bits at a specific frequency known as the baud rate. Baud rate is a measure of the speed of data transfer, expressed in bits per second (bps). Both UARTs must operate at about the same baud rate. The baud rate between the transmitting and receiving UARTs can only differ by about 10% before the timing of bits gets too far off.

Both UARTs must also must be configured to transmit and receive the same data packet structure.

Basics-of-UART-Communication-Specifications-Table

The UART that is going to transmit data receives the data from a data bus. The data bus is used to send data to the UART by another device like a CPU, memory, or microcontroller. Data is transferred from the data bus to the transmitting UART in parallel form. After the transmitting UART gets the parallel data from the data bus, it adds a start bit, a parity bit, and a stop bit, creating the data packet. Next, the data packet is output serially, bit by bit at the Tx pin. The receiving UART reads the data packet bit by bit at its Rx pin. The receiving UART then converts the data back into parallel form and removes the start bit, parity bit, and stop bits. Finally, the receiving UART transfers the data packet in parallel to the data bus on the receiving end:

Introduction-to-UART-Data-Transmission-Diagram

UART transmitted data is organized into packets. Each packet contains 1 start bit, 5 to 9 data bits (depending on the UART), an optional parity bit, and 1 or 2 stop bits:

Introduction-to-UART-Packet-Frame-and-Bits-2

Steps of UART TRANSMISSION

  1. The transmitting UART receives data in parallel from the data bus:

    Introduction-to-UART-Data-Transmission-Diagram-UART-Gets-Byte-from-Data-Bus

  2. The transmitting UART adds the start bit, parity bit, and the stop bit(s) to the data frame:

    Introduction-to-UART-Data-Transmission-Diagram-UART-Adds-Start-Parity-ad-Stop-Bits-2

  3. The entire packet is sent serially from the transmitting UART to the receiving UART. The receiving UART samples the data line at the pre-configured baud rate:

    Introduction-to-UART-Data-Transmission-Diagram-Transmitting-UART-Sends-Data-Packet-Serially-to-Receiving-UART

  4. The receiving UART discards the start bit, parity bit, and stop bit from the data frame:

    Introduction-to-UART-Data-Transmission-Diagram-UART-Removes-Start-Parity-and-Stop-Bits-2

  5. The receiving UART converts the serial data back into parallel and transfers it to the data bus on the receiving end:

    Introduction-to-UART-Data-Transmission-Diagram-Receiving-UART-Sends-Byte-to-Data-Bus-2

Wiring and Hardware

A serial bus consists of just two wires - one for sending data and another for receiving. As such, serial devices should have two serial pins: the receiver, RX, and the transmitter, TX.

It’s important to note that those RX and TX labels are with respect to the device itself. So the RX from one device should go to the TX of the other, and vice-versa. It’s weird if you’re used to hooking up VCC to VCC, GND to GND, MOSI to MOSI, etc., but it makes sense if you think about it. The transmitter should be talking to the receiver, not to another transmitter.

A serial interface where both devices may send and receive data is either full-duplex or half-duplex. Full-duplex means both devices can send and receive simultaneously. Half-duplex communication means serial devices must take turns sending and receiving.

But how is serial communication actually implemented at a signal level? In a variety of ways, actually. There are all sorts of standards for serial signaling. Let’s look at a couple of the more popular hardware implementations of serial: logic-level (TTL) and RS-232.

When microcontrollers and other low-level ICs communicate serially they usually do so at a TTL (transistor-transistor logic) level. TTL serial signals exist between a microcontroller’s voltage supply range - usually 0V to 3.3V or 5V. A signal at the VCC level (3.3V, 5V, etc.) indicates either an idle line, a bit of value 1, or a stop bit. A 0V (GND) signal represents either a start bit or a data bit of value 0.

51142c09ce395f0e7e000002

RS-232, which can be found on some of the more ancient computers and peripherals, is like TTL serial flipped on its head. RS-232 signals usually range between -13V and 13V, though the spec allows for anything from +/- 3V to +/- 25V. On these signals a low voltage (-5V, -13V, etc.) indicates either the idle line, a stop bit, or a data bit of value 1. A high RS-232 signal means either a start bit, or a 0-value data bit. That’s kind of the opposite of TTL serial.

51142cacce395f877e000006

Between the two serial signal standards, TTL is much easier to implement into embedded circuits. However the low voltage levels are more susceptible to losses across long transmission lines. RS-232, or more complex standards like RS-485, are better suited to long range serial transmissions.

Essentially, the UART acts as an intermediary between parallel and serial interfaces. On one end of the UART is a bus of eight-or-so data lines (plus some control pins), on the other is the two serial wires - RX and TX.

50e1cf30ce395fb227000000

UARTs do exist as stand-alone ICs, but they’re more commonly found inside microcontrollers. You’ll have to check your microcontroller’s datasheet to see if it has any UARTs. Some have none, some have one, some have many. For example, the Arduino Uno - based on the “old faithful” ATmega328 - has just a single UART, while the Arduino Mega - built on an ATmega2560 - has a whopping four UARTs.

As the R and T in the acronym dictate, UARTs are responsible for both sending and receiving serial data. On the transmit side, a UART must create the data packet - appending sync and parity bits - and send that packet out the TX line with precise timing (according to the set baud rate). On the receive end, the UART has to sample the RX line at rates according to the expected baud rate, pick out the sync bits, and spit out the data.

50d24680ce395f7172000000

More advanced UARTs may throw their received data into a buffer, where it can stay until the microcontroller comes to get it. UARTs will usually release their buffered data on a first-in-first-out (FIFO) basis. Buffers can be as small as a few bits, or as large as thousands of bytes.

Software UARTs

This is what we use mainly on the AlfaSat.

If a microcontroller doesn’t have a UART (or doesn’t have enough), the serial interface can be bit-banged - directly controlled by the processor. This is the approach Arduino libraries like SoftwareSerial take. Bit-banging is processor-intensive, and not usually as precise as a UART, but it works in a pinch!

RS 485

Modbus

Arduino Logic

Arduino Serial Input Basics

Introduction

Almost all serial input data can be covered by three simple situations:

  • A - when only a single character is required

  • B - when only simple manual input from the Serial Monitor is required

  • C - other

ch9a_se9

Serial Data is slow by Arduino Standards

When anything sends serial data to the Arduino it arrives into the Arduino input buffer at a speed set by the baud rate.

At 9600 baud about 960 characters arrive per second which means there is a gap of just over 1 millisecond between characters.

The Arduino can do a lot in 1 millisecond so the code that follows is designed not to waste time waiting when there is nothing in the input buffer even if all of the data has not yet arrived. Even at 115200 baud there is still 86 microseconds or 1376 Arduino instructions between characters.

And because data arrives relatively slowly it is easy for the Arduino to empty the serial input buffer even though all of the data has not yet arrived. Many make the mistake of assuming that something like while (Serial.available() > 0) { will pick up all the data that is sent. But it is far more likely that the WHILE will empty the buffer even though only part of the data has arrived.

Example 1: Receiving Single Characters

In very many cases all that is needed is to send a single character to the Arduino. Between the upper and lower case letters and the numeric characters there are 62 options. For example you could use ‘F’ for forward, ‘R’ for reverse and ‘S’ for stop.

Code to receive a single character is as simple as this:

#include <Arduino.h>

char receivedChar;
boolean newData = false;
void showNewData();
void recvOneChar();

void setup() {
    Serial.begin(9600);
    Serial.println("Arduino is Ready");
}

void loop() {
    recvOneChar();
    showNewData();
}

void recvOneChar() {
    if (Serial.available() > 0) {
        receivedChar = Serial.read();
        newData = true;
    }
}

void showNewData(){
    if (newData){
        Serial.print("This just in ...");
        Serial.println(receivedChar);
        newData = false;
    }
}

2020-09-04 10.42.19

Why code is organized into functions?

Even though this example is short and simple I have deliberately put the code to receive the character into a separate function called recvOneChar() as that makes it simple to add it into any other program. I also have the code for showing the character in the function showNewData() because you can change that to do whatever you want without upsetting the rest of the code.

Example 2: Receiving several characters from the Serial Monitor.

If you need to receive more than a single character from the Serial Monitor (perhaps you want to input people’s names) you will need some method of letting the Arduino know when it has received the full message. The simplest way to do this is to set the line-ending to newline.

This is done with the box at the bottom of the Serial Monitor window. You can choose between “No line ending”, “Newline”, “Carriage return” and “Both NL and CR”. When you select the “Newline” option a new-line character (‘\n’) is added at the end of everything you send.

image-20200904105123744

#include <Arduino.h>

const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data;
boolean newData = false;

void recvWithMarker();

void showNewData();

void setup() {
    Serial.begin(9600);
    Serial.println("Arduino is Ready");
}

void loop() {
    recvWithMarker();
    showNewData();
}

void recvWithMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;

    while (Serial.available() > 0 && !newData) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        } else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

image-20200904105909793

several chars

This version of the program reads all the characters into an array until it detects the Newline character as an end marker.

Example 3: A more Complete System

The simple system in Example 2 will work well with a sympathetic human who does not try to mess it up. But if the computer or person sending the data cannot know when the Arduino is ready to receive there is a real risk that the Arduino will not know where the data starts.

If you would like to explore this, change the end marker in the previous program from ‘\n’ to ‘>’ so that you can include the end marker in your text for illustration purposes. (You can’t manually enter a Newline character in the text you are sending from the Serial Monitor). And put the line ending back to “No line ending”

Now, with the revised code send “qwert>” and you will see that it behaves exactly the same as when you were using Newline as the end marker.

But if you try this “asdfg>zxcvb” you will only see the first part “asdfg”. And then if you send “qwert>” you will see “zxcvbqwert” because the Arduino has become confused and cannot know that it should have ignored “zxcvb”.

The answer to this problem is to include a start-marker as well as an end-marker.

#include <Arduino.h>

const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data;
boolean newData = false;

void recvWithMarker();

void showNewData();

void setup() {
    Serial.begin(9600);
    Serial.println("Arduino is Ready");
}

void loop() {
    recvWithMarker();
    showNewData();
}

void recvWithMarker() {
    static boolean recvInprogress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && !newData) {
        rc = Serial.read();
        if (recvInprogress) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            } else {
                receivedChars[ndx] = '\0'; // terminate the string
                ndx = 0;
                newData = true;
            }
        } else if (rc == startMarker) {
            recvInprogress = true;
        }
    }
}

void showNewData() {
    if (newData) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

2020-09-04 11.11.07

To see how it works try sending qwerty<asdfg>zxcvb and you will see that it ignores everything except “asdfg”.

In this program you will notice that there is a new variable called recvInProgress. This is necessary because a distinction needs to be made between unwanted characters that arrive before the start marker and the valid characters that arrive after the start marker.

How it works?

It is important to notice that each time the function recvWithEndMarker() or recvWithStartEndMarker() is called it reads whatever characters may have arrived in the serial input buffer and places them in the array receivedChars.

If there is nothing in the buffer recvWithEndMarker() does not waste time waiting.

In the case of recvWithStartEndMarker() all characters are discarded until the start-marker is detected.

If the end-marker has not yet arrived it will try again when loop() next repeats.

For best results it is important to ensure that loop() can repeat as quickly as possible - hundreds or even thousands of times per second.

How Many Characters Can be Received?

In the examples I have assumed that you will not need to receive more than 32 bytes. That can easily be altered by changing the value in the constant numChars.

Note that the 64 byte size of the Arduino serial input buffer does not limit the number of characters that you can receive because the code in the examples can empty the buffer faster than new data arrives.

Things that are not Used in the Example

You will notice that the examples here do not use any of these Arduino functions

  • Serial.parseInt()
  • Serial.parseFloat()
  • Serial.readBytes()
  • Serial.readBytesUntil()

All of these are blocking functions that prevent the Arduino from doing something else until they are satisfied, or until the timeout expires. The examples here do exactly the same job without blocking. That allows the Arduino to do other things while it is waiting for data to arrive.

serialEvent()

I don’t recommend using this function - I prefer to deal with the Serial data when it suits me. It behaves just as if you had this code as the last thing in loop().

if (Serial.available() > 0) {
  mySerialEvent();
}
Clearing the Input Buffer

It is probably worth mentioning that the poorly named Serial.flush() function does not empty the input buffer. It is only relevant when the Arduino is sending data and its purpose is to block the Arduino until all outgoing the data has been sent.

If you need to ensure the Serial input buffer is empty you can do so like this

while (Serial.available() >0 ){
  serial.read();
}
Receiving Numbers Rather Than Text

So far the examples have assumed you want to receive text. But perhaps you want to send a number or maybe a mix of text and numbers.

Example4: Receiving a single Number from the Serial Monitor

The simplest case is where you want to type a number into the Serial Monitor (I am assuming you have line-ending set to newline). Let’s assume you want to send the number 234. This is a variation on Example 2 and it will work with any integer value. Note that if you don’t enter a valid number it will show as 0 (zero).

#include <Arduino.h>

const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data;
boolean newData = false;
int dataNumber = 0;


void recvWithMarker();

void showNewNumber();

void setup() {
    Serial.begin(9600);
    Serial.println("Arduino is Ready");
}

void loop() {
    recvWithMarker();
    showNewNumber();
}

void recvWithMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    if (Serial.available() > 0) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        } else { // while we have just received a \n
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewNumber() {
    if (newData) {
        dataNumber = 0; // new for here
        dataNumber = atoi(receivedChars); // new for here
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        Serial.print("Data as Number ... ");
        Serial.println(dataNumber);
        newData = false;
    }
}

if the number is too long, it may exced the integer value range

2020-09-04 11.28.44

Example 5: Receiving and Parsing Several Pieces of Data

It is also straightforward to receive several pieces of data in a single message and parse the data to assign them to individual variables. This example assumes you send something like “<HelloWorld, 12, 24.7>”. This is an extension of Example 3.

A function called parseData() has been added and the function showParsedData() takes the place of showNewData() in the earlier example.

#include <Arduino.h>

const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data;
char tempChars[numChars]; // temporary array for use when parsing

// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;

boolean newData = false;


void recvWithStartEndMarkers();

void parseData();

void showParsedData();

void setup() {
    Serial.begin(9600);
    Serial.println("Arduino is Ready");
    Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
    Serial.println("Enter data in this style : <HelloWorld, 12, 3.14> ");
    Serial.println();
}

void loop() {
    recvWithStartEndMarkers();
    if (newData) {
        strcpy(tempChars, receivedChars);
        // this temporary copy is necessary to protect the original data
        // because strtok() used in parseData() replaces the commmas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;


    while (Serial.available() > 0 && !newData) {
        rc = Serial.read();

        if (recvInProgress) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            } else {
                receivedChars[ndx] = '\0'; //terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        } else if (rc = startMarker) {
            recvInProgress = true;
        }
    }

}

void parseData() {
    // split the data into its parts
    char *strtoKIndex; // this is used by strtok() as an index
    strtoKIndex = strtok(tempChars, ","); // get the first part - the string
    /*
     * char *strtok(char *s, const char *delim)
     strtok parses the string s into tokens.
     The first call to strtok should have s as its first argument.
     Subsequent calls should have the first argument set to NULL.
     If a token ends with a delimiter, this delimiting character is overwritten with a '\\0'
     and a pointer to the next character is saved for the next call to strtok.
     The delimiter string delim may be different for each call.
     */
    strcpy(messageFromPC, strtoKIndex); // copy the first part to message from pc
    strtoKIndex = strtok(NULL, ","); // this continues where the previous call left off
    integerFromPC = atoi(strtoKIndex);

    strtoKIndex = strtok(NULL, ","); // this continues where the previous call left off
    floatFromPC = atof(strtoKIndex);
}

void showParsedData(){
    Serial.print("Message ");
    Serial.println(messageFromPC);
    Serial.print("Integer ");
    Serial.println(integerFromPC);
    Serial.print("Float ");
    Serial.println(floatFromPC);
}

image-20200904115115546

2020-09-04 11.50.35

Binary Data

So far we have been receiving character data - for example the number 121 is represented by the characters ‘1’, ‘2’ and ‘1’. It is also possible to send that value as binary data in a single byte - it happens to be the Ascii value for the character ‘y’. Note that 121 in decimal is the same as 0x79 in HEX

Note that if you are sending binary data it is quite likely that you will need to send as data the same values that are used for the start- and end-markers.

The examples that follow assume that the binary data will NEVER include the byte values used for the start- and end-markers.

The examples that follow assume that the binary data will NEVER include the byte values used for the start- and end-markers. For simplicity I will continue to use < and > as the markers. The byte values for those characters are 0x3C and 0x3E. This will allow you to test the program from the Serial Monitor by sending, for example, <24y> which will be interpreted by the receiving program as the binary values 0x32, 0x34 and 0x79. These are the Ascii codes for 2, 4 and y.

Of course it would be more usual for binary data to be sent by another computer program - on another Arduino or on a PC.

Example 6: Program to Receive Binary Data
#include <Arduino.h>

const byte numBytes = 32;
byte receivedBytes[numBytes];
byte numReceived = 0;

boolean newData = false;


void recvBytesWithStartEndMarkers();
void showNewData();
void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvBytesWithStartEndMarkers();
    showNewData();
}

void recvBytesWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    byte startMarker = 0x3C;
    byte endMarker = 0x3E;
    byte rb;


    while (Serial.available() > 0 && !newData) {
        rb = Serial.read();

        if (recvInProgress) {
            if (rb != endMarker) {
                receivedBytes[ndx] = rb;
                ndx++;
                if (ndx >= numBytes) {
                    ndx = numBytes - 1;
                }
            }
            else {
                receivedBytes[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                numReceived = ndx;  // save the number for use when printing
                ndx = 0;
                newData = true;
            }
        }

        else if (rb == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() {
    if (newData) {
        Serial.print("This just in (HEX values)... ");
        for (byte n = 0; n < numReceived; n++) {
            Serial.print(receivedBytes[n], HEX);
            Serial.print(' ');
        }
        Serial.println();
        newData = false;
    }
}

image-20200904121224749

2020-09-04 12.11.44

Arduino Serial Examples

Arduino Read HEX from Serial

Simple Serial Read

serialRead() reads one byte at a time from the serial buffer, so in order to print out the whole sentence at once (it is actually still printing one byte at a time but the pc will receive it not interupted by newLines or other printString inside you loop) you must loop untill there are bytes in the serial buffer and and print right away that byte you just read. After that the loop can continue it’s tasks.

#include "Arduino.h"

int serIn; // var that hold the bytes in read from the serialBuffer.
void setup(){
    Serial.begin(9600);
}

void loop(){
    // simple feedback from Arduino Serial.println("Hello, World!")
    // only if there are bytes in the serial buffer execute the following code
    if (Serial.available()){
        // inform that Arduino heard you saying something
        Serial.print("Arduino heard you say: ");
        // keep reading and printing from serial until there are bytes in the serial buffer
        while (Serial.available()>0){
            serIn = Serial.read(); // read Serial
            Serial.print(serIn, BIN); // prints the character just read
        }
    }
    // the serial buffer is over just go to the line (or pass your favorite stop char)
    Serial.println();
    delay(1000);
}

image-20200904125223869

2020-09-04 12.51.58

Arduino Parse HEX

C/C++ Logic

Read and Parse Hex in CPP

Read and Parse Hex in C

Python Logic

https://github.com/blackdog70/mm485

AlfaSat Communication Protocol (ACP)

ACP Frame

image-20200904161300514

ACP Node Address

DEC BIN HEX ID DESCRIPTION
0 0b 0000 0x 00 OBC On Board Computer
1 0b 0001 0x 01 EPS Energy Power System
2 0b 0010 0x 02 TRX Telecommunication
3 0b 0011 0x 03 TOP Top Board
4 0b 0100 0x 04 SB Sensorboard
12 0b 1100 0x 0C GS_HW Groundstation Hardware
13 0b 1101 0x 0D GS_PC Groundstation Computer

ACP OBC Commands

ACP Sensorboard Querry Commands

DEC HEX CMD ID CMD TYPE TARGET ID VAR ID DESCRIPTION
0 0x00 STAT CHECK SB SENSORS Check sensors status
100 0x64 BMET GET BME TEM Get BME temperature
101 0x65 BMEP GET BME PRE Get BME pressure
102 0x66 BMEH GET BME HUM Get BME humidity
103 0x67 BMEG GET BME GAS Get BME gas
104 0x68 BMEA GET BME ALT Get BME altitude
110 0x69 BNOH GET BNO HED Get BNO Heading
111 0x6F BNOP GET BNO POS Get BNO Position
112 0x70 BNOS GET BNO SPD Get BNO Speed
120 0x78 GGC GET GG CPM Get Geiger CPM
121 0x79 RFU RFU RFU RFU RFU
130 0x82 SIV GET SI VIS Get SI VIS
131 0x83 SIR GET SI IR Get SI IR
132 0x84 SUV GET SI UV Get SI UV

ACP Sensorboard Response Data Definitions

Types reference in C& C++ :

Signed Type Unsigned Type Description
int8_t uint8_t Integer type with a width of exactly 8, 16, 32, or 64 bits.
For signed types, negative values are represented using 2’s complement.
No padding bits.
Optional: These typedefs are not defined if no types with such characteristics exist.*
int16_t uint16_t SAME
int32_t uint32_t SAME

Type range in AlfaSat (NOT YET CONFIRMED):

Representing Integer (unsigned 8 bit) uint8                
bit 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
val 128 64 32 16 8 4 2 1
max-until 255 127 63 31 15 7 3 1
bits                
range 0 ~ 255              
Representing Integer (signed 8 bit) int8                
bit 2^6 2^5 2^4 2^3 2^2 2^1 2^0 SIGN
val 64 32 16 8 4 2 1 0/1
max-until 127 63 31 15 7 3 1 0/1
bits               0/1
range -127 ~ 0 ~ 127              
Representing Integer (unsigned 16 bit) uint16                                
bit 2^15 2^14 2^13 2^12 2^11 2^10 2^9 2^8 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
val 32768 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1
max-until 65535 32767 16383 8191 4095 2047 1023 511 255 127 63 31 15 7 3 1
bits                                
range 0 ~ 65535                              
Representing Integer (signed 16 bit) int16                                
bit 2^14 2^13 2^12 2^11 2^10 2^9 2^8 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 SIGN
val 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1 0/1
max-until 32767 16383 8191 4095 2047 1023 511 255 127 63 31 15 7 3 1 0/1
bits                               0/1
range -32767 ~ 0 ~ 32767                              

FOR FLOAT PRECISION =2

So, 1123.23 == 112323

Integer Data Types
C type stdint.h type Bits Sign Range
char uint8_t 8 Unsigned 0 .. 255 | 2.55
signed char int8_t 8 Signed -128 .. 127 | 1.27 +-
unsigned short uint16_t 16 Unsigned 0 .. 65,535 | 655.35
short int16_t 16 Signed -32,768 .. 32,767 | 32.767 +-
unsigned int uint32_t 32 Unsigned 0 .. 4,294,967,295 | 42949672. 95
int int32_t 32 Signed -2,147,483,648 .. 2,147,483,647
unsigned long long uint64_t 64 Unsigned 0 .. 18,446,744,073,709,551,615
long long int64_t 64 Signed -9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807
Dfor Parameter Min Max Unit Dtype Exp Exp.HEX LEN NOte
0x00 Status 0 15 Boolean char [4] 0b1111 0x0F 1 byte Int
0x64 Temperature -40.0 85.00 °C uint16 31.09 0xC25 2 byte Float
  Pressure 300.0 1100.00 hPa unit32 917.44 0x16660 4 byte Float
  Humidity 0.00 100.00 % uint32 19.59 0x7A7 4 byte Float
  Gas 0.00 100.00 KOhms uint32 32.76 0xCCC 4 byte Float
  Altitude 0.00 30000.00 m uint32 823.23 0x14193 4 byte Float
  Heading 0.00 360.00 ° uint16 355.63   2+2 Float
  Position(x,y) 0.00 360.00 ° uint16     2+2 Float
  Speed 0.00 100.00 m/s uint16     2+2 Float
  CPM 0 500 - uint16 204 0xCC 2 Int
  VIS 0 300 - uint16 262 0x106 2 Int
  IR 0 300 - uint16 258 0x102 2 Int
  UV 0.00 99.00 - uint16 1.03 0x67 2 Float

libacp

pylibacp