{"id":4253,"date":"2020-06-10T20:00:29","date_gmt":"2020-06-10T18:00:29","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4253"},"modified":"2025-12-27T17:25:37","modified_gmt":"2025-12-27T16:25:37","slug":"datas-life-comes-full-circle-or-the-circular-buffer","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/datas-life-comes-full-circle-or-the-circular-buffer\/","title":{"rendered":"Data\u2019s Life Comes Full Circle, or: The Circular Buffer"},"content":{"rendered":"\n<p>While further developing the library for the <a href=\"https:\/\/sklep.msalamon.pl\/?s=nrf24&amp;post_type=product&amp;utm_source=blog&amp;utm_medium=article&amp;utm_campaign=nrf24&amp;utm_content=Text\">nRF24L01+<\/a> module, I decided to use ring buffers. I figured that this is a good moment to first introduce you to the topic before I show how I implemented them for radio communication. What is this data storage structure and how do you use it?<\/p>\n\n\n\n<!--more-->\n\n\n\n<h1 class=\"wp-block-heading\"><figure><a href=\"https:\/\/sklep.msalamon.pl\/kategoria-produktu\/dev-boardy\/stm32-nucleo\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=ring_buffer&amp;utm_content=nucleo\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg\" alt=\"\" width=\"1200\" height=\"400\" class=\"aligncenter wp-image-1593 size-full\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-768x256.jpg 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\"><\/a><\/figure><\/h1>\n\n\n\n<h1 class=\"wp-block-heading\">Ring buffer<\/h1>\n\n\n\n<p>They call it different things: circular, cyclic, ring. All of these names generally refer to the same thing. What is it, really, and why not just use a regular array?<\/p>\n\n\n\n<p>Exactly. You can just put data into an array and read that array. The simplest solution and probably sufficient in many places. The problem comes when we ask ourselves a few questions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Where in the array should I put new data, or read from?<\/li>\n\n\n\n<li>How many elements can I still write into the array?<\/li>\n\n\n\n<li>Is the current position the current fill level?<\/li>\n\n\n\n<li>If I read a byte from position zero, should I write the next new data there, or at the end?<\/li>\n\n\n\n<li>Have the data in the array already been read\/used?<\/li>\n\n\n\n<li>What if I fill the array? I have to remember its size so I don\u2019t go out of range.<\/li>\n<\/ul>\n\n\n\n<p>There can be many more such questions. Arrays are great for temporary things like a buffer that we\u2019re about to push to UART. In that case I always use an array in a one-shot manner.<\/p>\n\n\n\n<p>A ring buffer will be useful if we want our data to live longer and across a larger part of the program. Besides, it brings order, because things like the amount of unprocessed data or overflow are taken care of automatically.<\/p>\n\n\n\n<p>For example, when communicating with the nRF24, data that arrives at a \u201crandom\u201d moment via an interrupt lands in the receive buffer, and we don\u2019t want to deal with that data in the interrupt service routine. We can, for example, handle it after some specific character arrives. We\u2019ll process it only when there\u2019s appropriate time. Before we deal with it, more data may arrive. We need to store it all somewhere.<\/p>\n\n\n\n<p>Now the other side. We want to transmit something via the nRF24. We can simply write what we want to send into the chip and it will send it. What if we have more data to send than the chip can transmit at once? Wait idly for the first packet to be sent? Of course we don\u2019t like waiting like that \ud83d\ude42<\/p>\n\n\n\n<p>You can write 100 bytes into the ring buffer and send them in chunks at moments when there is time and the transmitter is free. The sending procedure should fetch data from the buffer by itself without involving us.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How a ring buffer works<\/h2>\n\n\n\n<p>A ring buffer is basically a FIFO queue (First In First Out). This means that the data you write to the buffer is the first data that will be taken out of it. FIFOs are one of the most popular buffering forms.<\/p>\n\n\n\n<p>So why \u201cring\u201d or \u201ccyclic\u201d? Because the theoretical arrangement of the data resembles a circle \ud83d\ude42 This is well visualized by the image from Wikipedia:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1.png\" alt=\"\" class=\"wp-image-1544\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1.png 800w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1-300x300.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1-150x150.png 150w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1-768x768.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1-24x24.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1-36x36.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/06\/Bufor_cykliczny_1-80x80.png 80w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>In the picture you have a cyclic buffer of size 8 bytes. Look at the yellow arrow, which is the pointer to the next write. When it reaches byte no. 8, the next place to write in the buffer will be byte no. 1. Similarly for reading. Passing the eighth byte will cause the next one to read to be the first byte. That\u2019s where the circular interpretation of this data structure as a circular space comes from.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do you make a cyclic structure in memory?<\/h3>\n\n\n\n<p>Unfortunately, that cyclic nature in theory cannot be directly translated into memory in a microcontroller. RAM in an MCU is contiguous and much larger than our buffer. The buffer, in turn, is somewhere in the middle of memory. Let\u2019s assume we have this 8-byte buffer at addresses 0x10\u00f70x17. If the write pointer is at address 0x17, then writing a byte there and incrementing will not automatically \u201croll back\u201d to 0x10. Normally this pointer will land at 0x18, i.e. it will <strong>go out of the array<\/strong>. That\u2019s exactly what we don\u2019t want.<\/p>\n\n\n\n<p>We need to help the pointer return to position zero. How do we do that? After incrementing the pointer, check whether it went out of range. You can do this in two ways:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Using if(WritePointer > BufferSize-1) { WritePointer = 0};<\/li>\n\n\n\n<li>Simply perform modulo division on the pointer: WritePointer %= BufferSize;<\/li>\n<\/ul>\n\n\n\n<p>I always choose the second variant. Modulo division by the buffer size will never allow you to go beyond the bounds of the array size.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Helper elements of the buffer<\/h3>\n\n\n\n<p>You\u2019ve probably already noticed that we need something more than just the array we\u2019ll be writing to. We need write and read pointers. What are they for?<\/p>\n\n\n\n<p>We want writing and reading from the buffer not to depend on providing the index of the cell we want to use. It should happen in the background, away from the user. So the structure itself must remember which cell the next byte should be written to, and which one should be read from.<\/p>\n\n\n\n<p>These pointers are Head and Tail. The naming most likely comes from a snake. The head of the snake is where subsequent data will be written, the tail points to the first byte to be read.<\/p>\n\n\n\n<p>You probably played Snake on a Nokia, right? Do you remember what it means when the head catches up to the tail? Game Over. It\u2019s similar here. If the head catches up to the tail, it means there is no more space in the buffer.<\/p>\n\n\n\n<p>On the other hand, you\u2019ll reach such a Game Over when trying to read from an empty buffer, i.e. when the tail catches up to the head.<\/p>\n\n\n\n<p>You can detect these two extreme situations and handle them somehow. More often you will deal with the empty buffer\u2014after all, we aim to process all data contained in it. Then it\u2019s worth signaling that there\u2019s nothing to read.<\/p>\n\n\n\n<p>So what will our buffer look like at this point? It will be a structure with an array and two \u201cpointers\u201d addressing that array. This is the simplest form of a buffer.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#define BUFFER_SIZE 32\n\ntypedef struct\n{\nuint8_t Buffer[BUFFER_SIZE];\nuint8_t Head;\nuint8_t Tail;\n} RingBuffer;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Writing to the buffer<\/h3>\n\n\n\n<p>From the point of view of using the buffer, we really need two functions: writing and reading a byte from the buffer. I\u2019ll take writing first.<\/p>\n\n\n\n<p>A freshly created structure has zeros in its fields, so the&nbsp;<em>Head&nbsp;<\/em>and&nbsp;<em>Tail<\/em> pointers point to the first cell of the buffer array. To write something to the buffer you must:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Make sure there is space<\/li>\n\n\n\n<li>Write the data into the next free place<\/li>\n\n\n\n<li>Increment the write pointer, remembering the \u201ccyclic\u201d nature<\/li>\n<\/ol>\n\n\n\n<p>And that\u2019s it! How do you make sure we have space to write? There are several ways, including adding an additional field in the structure that counts the number of elements in the buffer, which is quite a good solution.<\/p>\n\n\n\n<p>However, the simplest method will be to check whether the next write pointer in order (the head) will \u201chit\u201d the snake\u2019s tail.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int8_t WriteToBuffer(RingBuffer *Buffer, uint8_t Data)\n{\n\tuint8_t TempHead;\n\n\tTempHead = (Buffer-&amp;gt;Head + 1) % BUFFER_SIZE;\n\n\tif( TempHead == Buffer-&amp;gt;Tail) \/\/ No room for new data\n\t{\n\t\treturn -1;\n\t}\n\telse\n\t{\n            \/\/ Write to buffer\n\t}\n\n\treturn 0;\n}<\/pre>\n\n\n\n<p>A helper variable TempHead helps me with this, where I keep the computed next head position. You can do without it, but this will be more readable. Next, I compare it with the current tail and if they are equal I return error -1. If they are different, it means there is space and we can write.<\/p>\n\n\n\n<p>The first point from the list is satisfied. What do the second and third points look like, i.e. writing and incrementing?<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Buffer-&amp;gt;Buffer[Buffer-&amp;gt;Head] = Data;\n\nBuffer-&amp;gt;Head++;\nBuffer-&amp;gt;Head %= BUFFER_SIZE;<\/pre>\n\n\n\n<p>Knowing there is space, I can safely write the byte and increment the write pointer to the next \u201cfree\u201d cell.<\/p>\n\n\n\n<p>So the whole function looks like this<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int8_t WriteToBuffer(RingBuffer *Buffer, uint8_t Data)\n{\n\tuint8_t TempHead;\n\n\tTempHead = (Buffer-&amp;gt;Head + 1) % BUFFER_SIZE;\n\n\tif( TempHead == Buffer-&amp;gt;Tail) \/\/ No room for new data\n\t{\n\t\treturn -1;\n\t}\n\telse\n\t{\n            Buffer-&amp;gt;Buffer[Buffer-&amp;gt;Head] = Data;\n\n            Buffer-&amp;gt;Head++;\n            Buffer-&amp;gt;Head %= BUFFER_SIZE;\n\t}\n\n\treturn 0;\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Reading from the buffer<\/h3>\n\n\n\n<p>Now it would be good to read a byte that is already written into the buffer. Reading is analogous to writing, except I don\u2019t check whether there is space in the next cell, but I check whether <em>Tail<\/em> has already become equal to <em>Head<\/em>. If so, there is nothing to read.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int8_t ReadFromBuffer(RingBuffer *Buffer, uint8_t *Data)\n{\n\tif( Buffer-&amp;gt;Tail == Buffer-&amp;gt;Head) \/\/ No data to read\n\t{\n\t\treturn -1;\n\t}\n\telse\n\t{\n\t\t*Data = Buffer-&amp;gt;Buffer[Buffer-&amp;gt;Tail];\n\n\t\tBuffer-&amp;gt;Tail++;\n\t\tBuffer-&amp;gt;Tail %= BUFFER_SIZE;\n\n\t\tBuffer-&amp;gt;Elements--;\n\t}\n\treturn 0;\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">How many bytes fit in such a buffer?<\/h3>\n\n\n\n<p>It may seem simple and obvious that if I have a 32-byte array, then I can fit 32 bytes.<\/p>\n\n\n\n<p>Well, no. In such an array I can store 31 bytes. Notice that when writing, if there is no free space in front of the write pointer, I won\u2019t write anything into the current position. That\u2019s why one byte must always be \u201cfree\u201d.<\/p>\n\n\n\n<p>Why did I do it this way? Just ask a simple question: If&nbsp;<em>Head<\/em> and&nbsp;<em>Tail<\/em> are equal, is the buffer full or empty? Here lies, contrary to appearances, a solid problem that cannot be solved without additional indicators. There are at least three solutions, or at least that many I know at the moment:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Using one \u201cfree\u201d byte in the array as an empty\/full indicator. That\u2019s what I did in the examples here.<\/li>\n\n\n\n<li>Counting elements on write and subtracting them on read in an additional structure field. Effective as long as we don\u2019t heavily use the buffer with interrupts or an RTOS.\u00a0 Then additional synchronization methods are needed. Bonus: we easily know how much data is available in the buffer before we start reading it.<\/li>\n\n\n\n<li>Combining the two methods above. That\u2019s what I ultimately used with the nRF24 because of the bonus.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Additional functions of ring buffers<\/h3>\n\n\n\n<p>You can add many interesting helper functions depending on the application. These can be things like:<\/p>\n\n\n\n<p><strong>Returning the number<\/strong> of elements in the buffer \/ free slots. Useful when reading the entire buffer.<\/p>\n\n\n\n<p><strong>Flush<\/strong>, i.e. clearing the buffer. Zeroing&nbsp;<em>Head&nbsp;<\/em>and&nbsp;<em>Tail&nbsp;<\/em> in the event of an error. For example, when the element counter diverges from the actual buffer state (based on the pointers) or on overflows.<\/p>\n\n\n\n<p><strong>Dynamic buffer size.<\/strong> I mean generating several buffers of different lengths, not dynamically adding and removing elements.<\/p>\n\n\n\n<p><strong>If you know any other interesting functions, let me know in the comments.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>A cyclic buffer is one of the nicer methods of buffering data. Very often you can use this method to collect data from sensors. You collect in an interrupt, and for example after collecting 100 samples, you read them all and process them elsewhere in the program.<\/p>\n\n\n\n<p>I encourage you to experiment and improve the buffer. Also adding or removing functions depending on the project\u2019s needs is cool. I usually do \ud83d\ude42<\/p>\n\n\n\n<p>This time I\u2019m not posting code. A buffer a bit more expanded than here in the article will be in the third part about the nRF24 coming soon.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/?s=nrf24&amp;post_type=product\/&amp;utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=ring_buffer&amp;utm_content=nrf24\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner.jpg\" alt=\"\" class=\"wp-image-1528\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/05\/nRF24L01-baner-160x53.jpg 160w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p><span>If you noticed an error, disagree with something, would like to add something important, or simply feel like you\u2019d like to discuss this topic, write a comment. Remember that the discussion should be polite and in accordance with the rules of the Polish language.<\/span><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4253&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;Data\u2019s Life Comes Full Circle, or: The Circular Buffer&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>While further developing the library for the nRF24L01+ module, I decided to use ring buffers. I figured that this is a good moment to first introduce you to the topic before I show how I implemented them for radio communication. What is this data storage structure and how do you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3449,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[175,176],"class_list":["post-4253","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-electronics","tag-programming"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4253","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4253"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4253\/revisions"}],"predecessor-version":[{"id":4369,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4253\/revisions\/4369"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3449"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}