--- a/SOM6Target/plc_SOM6_main_retain.c Thu Sep 16 11:45:11 2021 +0200
+++ b/SOM6Target/plc_SOM6_main_retain.c Tue Oct 05 09:29:49 2021 +0200
@@ -1,328 +1,209 @@
-#include <alchemy/event.h>
-#include <alchemy/mutex.h>
-#include <rtdm/spi_apf28_rtdm_ioctl.h>
-#include <xenomai/init.h>
-/* SPI configurable parameters */
-/* --------------------------- */
-#define TEST_SPI_CLK_PHASE RTDM_SPI_CLKPHASE_LOW
-#define TEST_SPI_CLK_POLARITY RTDM_SPI_CLKPOLARITY_LOW
-#define TEST_SPI_SPEED 20000000
-#define TEST_SPI_BITS_PER_WORD RTDM_SPI_8BPW
-#define TEST_SPI_CHIPSELECT1 RTDM_SPI_SS0
-#define TEST_SPI_CHIPSELECT2 RTDM_SPI_SS0
-/* Use the DMA from transfer > 4 bytes */
-#define TEST_SPI_DMA_BYTES_MIN 4
-#define NVRAM_SIZE 0x8000
+#define NVRAM_SIZE 0x10000
#define RETAIN_BUFFER_SIZE (NVRAM_SIZE - IDLEN)
-static RT_TASK RETAIN_task;
-static RT_MUTEX RETAIN_Mutex;
-static RT_EVENT RETAIN_Event;
+static void *RETAIN_handle; +static pthread_t RETAIN_thread; +static long RETAIN_last_written = 0; -/* Data protected by mutex */
- unsigned char cmd[CMDSIZE];
+/* Data protected by atomic lock */ unsigned char vars[RETAIN_BUFFER_SIZE];
+} buf[2] = {[0 ... 1] = {.lock=0, .full=0}}; static unsigned short actual_size;
-static int retain_busy = 0;
-/* 0 : PLC can update. No SPI transmission undergoing
- 1 : PLC cannot update. SPI transmission undergoing */
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-static uint8_t rcmd[] = {
+void RETAIN_thread_proc(void *arg) + while (wait_RT_to_nRT_signal(RETAIN_handle) == 0) { + int last_written = __atomic_load_n(&RETAIN_last_written, __ATOMIC_SEQ_CST); + int try_buf_idx = last_written; -int SPI_Read(void *buf, unsigned int len){
- if (ioctl(fd_spi, RTDM_SPI_LOCK_CS_SET, &uint) < 0) {
- printf("Failed to lock CS\n");
+ struct buf_s *selected_buf = &buf[try_buf_idx]; + long previous_lock_state = AtomicCompareExchange( + got_lock = previous_lock_state == BUFFER_FREE; + if(selected_buf->full){ + // Seek to begining of NVRAM + status = lseek(fd_nvram, 0, SEEK_SET); + fprintf(stderr, "Failed to seek before write to memory. ERR : %d\n", status); + status = write(fd_nvram, &selected_buf->data, actual_size + IDLEN); + fprintf(stderr, "Failed to write memory. ERR : %d %d\n", status, errno); + selected_buf->full = 0; + try_buf_idx = 1-try_buf_idx; - status = write(fd_spi, rcmd, ARRAY_SIZE(rcmd));
- fprintf(stderr, "Failed to send read command. ERR : %d\n", status);
+static int initlevel = 0; + for(int idx=0; idx<2; idx++){ + struct buf_s *selected_buf = &buf[idx]; + bzero(selected_buf, sizeof(struct buf_s));
- if (ioctl(fd_spi, RTDM_SPI_LOCK_CS_SET, &uint) < 0) {
- printf("Failed to unlock CS\n");
- size = read(fd_spi, buf, len);
- fprintf(stderr, "Failed to read %d bytes on the SPI bus. size : %d\n",
+ if(!(RETAIN_handle = create_RT_to_nRT_signal("RETAIN_pipe"))){ + fprintf(stderr, "RETAIN RT nRT pipe init error\n");
-int SPI_Write(void *buf, unsigned int len){
- status = write(fd_spi, buf, len);
- fprintf(stderr, "Failed to write memory. ERR : %d\n", status);
-static void SPI_init(void)
/* Open the SPI RTDM device */
- if ((fd_spi = open("/dev/rtdm/spi_apf28_rtdm", 0)) < 0) {
- printf("rt_spi_open error\n");
+ if ((fd_nvram = open("/dev/mtd0", O_RDWR|O_SYNC)) < 0) { + fprintf(stderr, "spi RAM open error %d %d\n", fd_nvram, errno); + /* Read the whole NVRAM at start */ + struct buf_s *selected_buf = &buf[0]; + size = read(fd_nvram, (void*) &selected_buf->data, NVRAM_SIZE); + if (size != NVRAM_SIZE) { + fprintf(stderr, "Failed to read %d bytes on the SPI bus. size : %d\n", size); - /* Bus configuration */
- uint = TEST_SPI_CLK_PHASE;
- if (ioctl(fd_spi, RTDM_SPI_CLKPHASE_SET, &uint) < 0) {
- printf("Failed to configure the clock phase\n");
- if (ioctl(fd_spi, RTDM_SPI_CLKPHASE_GET, &uint) < 0) {
- printf("Failed to get the clock phase\n");
- uint = TEST_SPI_CLK_POLARITY;
- if (ioctl(fd_spi, RTDM_SPI_CLKPOLARITY_SET, &uint) < 0) {
- printf("Failed to configure the clock polarity\n");
- if (ioctl(fd_spi, RTDM_SPI_CLKPOLARITY_GET, &uint) < 0) {
- printf("Failed to get the clock polarity\n");
- ulong = TEST_SPI_SPEED;
- if (ioctl(fd_spi, RTDM_SPI_FREQ_SET, &ulong) < 0) {
- printf("Failed to configure the frequency\n");
- if (ioctl(fd_spi, RTDM_SPI_FREQ_GET, &ulong) < 0) {
- printf("Failed to get the frequency\n");
- uint = TEST_SPI_BITS_PER_WORD;
- if (ioctl(fd_spi, RTDM_SPI_BITSPERWORD_SET, &uint) < 0) {
- printf("Failed to configure the BPW\n");
- if (ioctl(fd_spi, RTDM_SPI_BITSPERWORD_GET, &uint) < 0) {
- printf("Failed to get the BPW\n");
- uint = TEST_SPI_CHIPSELECT1;
- if (ioctl(fd_spi, RTDM_SPI_CHIPSELECT_SET, &uint) < 0) {
- printf("Failed to configure the chip select\n");
- if (ioctl(fd_spi, RTDM_SPI_CHIPSELECT_GET, &uint) < 0) {
- printf("Failed to get the chip select\n");
- /* DMA usage definition */
- uint = TEST_SPI_DMA_BYTES_MIN;
- if (ioctl(fd_spi, RTDM_SPI_DMA_SET, &uint) < 0) {
- printf("Failed to configure the DMA threshold\n");
- if (ioctl(fd_spi, RTDM_SPI_DMA_GET, &uint) < 0) {
- printf("Failed to get the DMA threshold\n");
+ if(err = pthread_create(&RETAIN_thread, NULL, (void*) &RETAIN_thread_proc, NULL)) { + fprintf(stderr, "Failed to create retain SPI thread. Error code: %d.\n", err);
- /* Prepare for future write commands */
- /* Set Sequencial access mode */
- // status = write(fd_spi, mbuf, ARRAY_SIZE(mbuf));
- printf("RETAIN : Failed to change mode. ERR : %d\n", status);
- // TODO: remove this !!!
- /* Read the whole NVRAM at start */
- SPI_Read(&priv.buf, NVRAM_SIZE);
-void RETAIN_task_proc(void *arg)
- while (!rt_event_wait(&RETAIN_Event, 1, &msk, EV_ANY, TM_INFINITE)) {
- if(rt_mutex_acquire(&RETAIN_Mutex, TM_INFINITE)) return;
- SPI_Write(&priv, CMDSIZE + actual_size + IDLEN);
- if(rt_event_clear(&RETAIN_Event, 1, NULL)) return;
- if(rt_mutex_release(&RETAIN_Mutex)) return;
-void InitRetain(void) /* TODO return error and care */
- if(rt_event_create (&RETAIN_Event, "RETAIN_Event", 0, 0))
- if(rt_mutex_create (&RETAIN_Mutex, "RETAIN_Mutex"))
- if(rt_task_create(&RETAIN_task, "RETAIN_task", 0, 50, T_JOINABLE))
- SPI_init(); /*TODO if error */
- if(rt_task_start(&RETAIN_task, &RETAIN_task_proc, NULL))
- while(!NVRAM_Done && count--){
- printf("NVRAM init timeout\n");
+ unblock_RT_to_nRT_signal(RETAIN_handle); + delete_RT_to_nRT_signal(RETAIN_handle); - rt_task_delete(&RETAIN_task);
- rt_task_join(&RETAIN_task);
- rt_mutex_delete(&RETAIN_Mutex);
- rt_event_delete(&RETAIN_Event);
+ pthread_join(RETAIN_thread, NULL); -void ValidateRetainBuffer(void)
+static int RETAIN_got_lock = 0; +static struct buf_s *RETAIN_selected_buf; +// called at beginning of publish, before collecting +// RETAIN variables from PLC +void InValidateRetainBuffer(void)
- memcpy(priv.buf.id, PLC_ID, IDLEN);
- rt_mutex_release(&RETAIN_Mutex);
- rt_event_signal(&RETAIN_Event, 1);
+ int last_written = __atomic_load_n(&RETAIN_last_written, __ATOMIC_SEQ_CST); + int try_buf_idx = 1-last_written; + while(!RETAIN_got_lock){ + RETAIN_selected_buf = &buf[try_buf_idx]; + RETAIN_idx = try_buf_idx; + long previous_lock_state = AtomicCompareExchange( + &RETAIN_selected_buf->lock, + RETAIN_got_lock = previous_lock_state == BUFFER_FREE; + // // Wrting zero in RAM to "invalidate" makes no sense since it still + // // has to be copied to SPI NVRAM + // if(RETAIN_got_lock){ + // bzero(&RETAIN)selected_buf.id[0], IDLEN); -void InValidateRetainBuffer(void)
+// called at the end of publish, after collecting +// RETAIN variables from PLC +void ValidateRetainBuffer(void) - int ret = rt_mutex_acquire(&RETAIN_Mutex, TM_NONBLOCK);
- if(ret == -EWOULDBLOCK){
- /* mutex was unavailable */
- /* invalidate that buffer */
- bzero(&priv.buf.id[0], IDLEN);
+ // // Done at init once for all + // memcpy(priv.buf.id, PLC_ID, IDLEN); + RETAIN_selected_buf->full = 1; + &RETAIN_selected_buf->lock, + __atomic_store_n(&RETAIN_last_written, RETAIN_idx, __ATOMIC_SEQ_CST); + unblock_RT_to_nRT_signal(RETAIN_handle);
- //printf("invalidate retain\n");
int CheckRetainBuffer(void)
/* compare RETAIN ID buffer with MD5 */
/* return true if identical */
+ struct buf_s *selected_buf = &buf[0];
- res = memcmp(&priv.buf.id[0], PLC_ID, IDLEN) == 0;
+ res = memcmp(&selected_buf->data.id, PLC_ID, IDLEN) == 0; + // PLC_ID is expected in both buffer after checking + // so that it is copied to NVRAM later + for(int idx=0; idx<2; idx++){ + struct buf_s *selected_buf = &buf[idx]; + memcpy(&selected_buf->data.id, PLC_ID, IDLEN); void Retain(unsigned int offset, unsigned int count, void *p)
- if(!retain_busy && offset + count < RETAIN_BUFFER_SIZE){
+ if(RETAIN_got_lock && offset + count < RETAIN_BUFFER_SIZE){ /* write in RETAIN buffer at offset*/
actual_size = offset + count;
- memcpy(&priv.buf.vars[offset], p, count);
+ memcpy(&RETAIN_selected_buf->data.vars[offset], p, count); void Remind(unsigned int offset, unsigned int count, void *p)
- if(!retain_busy && offset + count < RETAIN_BUFFER_SIZE)
+ struct buf_s *selected_buf = &buf[0]; + if(offset + count < RETAIN_BUFFER_SIZE) /* read at offset in RETAIN buffer */
- memcpy(p, &priv.buf.vars[offset], count);
+ memcpy(p, &selected_buf->data.vars[offset], count);