#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <string.h>
#include <rc/time.h>
#include <rc/pru.h>
#define PRU0_STATE "/dev/remoteproc/pruss-core0/state"
#define PRU1_STATE "/dev/remoteproc/pruss-core1/state"
#define PRU0_FW "/dev/remoteproc/pruss-core0/firmware"
#define PRU1_FW "/dev/remoteproc/pruss-core1/firmware"
#define PRU_ADDR 0x4A300000
#define PRU_LEN 0x80000
#define PRU_SHAREDMEM 0x10000
static volatile unsigned int* shared_mem_32bit_ptr = NULL;
int rc_pru_start(int ch, const char* fw_name)
{
int fd, ret;
char buf[64];
if(ch!=0 && ch!=1){
fprintf(stderr, "ERROR in rc_pru_start, PRU channel must be 0 or 1\n");
return -1;
}
if(fw_name==NULL){
fprintf(stderr, "ERROR in rc_pru_start, received NULL pointer\n");
return -1;
}
memset(buf,0,sizeof(buf));
snprintf(buf, sizeof(buf), "/lib/firmware/%s", fw_name);
if(access(buf, F_OK)!=0){
fprintf(stderr, "ERROR in rc_pru_start, requested firmware %s doesn't exist in /lib/firmware\n", fw_name);
return -1;
}
if(rc_pru_stop(ch)) return -1;
if(ch==0) fd=open(PRU0_FW, O_WRONLY);
else fd=open(PRU1_FW, O_WRONLY);
if(fd==-1){
perror("ERROR in rc_pru_start opening remoteproc driver");
fprintf(stderr,"need to be root to use the pru\n");
return -1;
}
ret = write(fd, fw_name, strlen(fw_name));
close(fd);
if(ret==-1){
perror("ERROR in rc_pru_start setting firmware name");
return -1;
}
if(ch==0) fd=open(PRU0_STATE, O_WRONLY);
else fd=open(PRU1_STATE, O_WRONLY);
if(fd==-1){
perror("ERROR in rc_pru_start opening remoteproc driver");
fprintf(stderr,"PRU probably not enabled in device tree\n");
return -1;
}
ret=write(fd, "start", 5);
close(fd);
if(ret==-1){
perror("ERROR in rc_pru_start starting remoteproc");
return -1;
}
rc_usleep(250000);
if(ch==0) fd=open(PRU0_STATE, O_RDONLY);
else fd=open(PRU1_STATE, O_RDONLY);
if(fd==-1){
perror("ERROR in rc_pru_start opening remoteproc driver");
fprintf(stderr,"PRU probably not enabled in device tree\n");
return -1;
}
memset(buf,0,sizeof(buf));
ret=read(fd, buf, sizeof(buf));
close(fd);
if(ret==-1){
perror("ERROR in rc_pru_start reading state");
return -1;
}
if(strcmp(buf,"running\n")){
fprintf(stderr,"ERROR: in rc_pru_init, pru%d failed to start\n", ch);
fprintf(stderr,"expected state to become 'running', instead is: %s\n",buf);
return -1;
}
return 0;
}
volatile uint32_t* rc_pru_shared_mem_ptr(void)
{
int fd;
volatile unsigned int* map;
if(shared_mem_32bit_ptr!=NULL){
return shared_mem_32bit_ptr;
}
fd=open("/dev/mem", O_RDWR | O_SYNC);
if(fd==-1){
perror("ERROR: in rc_pru_shared_mem_ptr could not open /dev/mem");
fprintf(stderr, "Need to be root to access PRU shared memory\n");
return NULL;
}
map = mmap(0, PRU_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PRU_ADDR);
if(map==MAP_FAILED){
perror("ERROR in rc_pru_shared_mem_ptr failed to map memory");
close(fd);
return NULL;
}
close(fd);
shared_mem_32bit_ptr = map + PRU_SHAREDMEM/4;
return shared_mem_32bit_ptr;
}
int rc_pru_stop(int ch)
{
int fd, ret;
char buf[64];
if(ch!=0 && ch!=1){
fprintf(stderr, "ERROR in rc_pru_stop, PRU channel must be 0 or 1\n");
return -1;
}
if(ch==0) fd=open(PRU0_STATE, O_RDONLY);
else fd=open(PRU1_STATE, O_RDONLY);
if(fd==-1){
perror("ERROR in rc_pru_stop opening remoteproc driver");
fprintf(stderr,"PRU probably not enabled in device tree\n");
return -1;
}
memset(buf,0,sizeof(buf));
ret=read(fd, buf, sizeof(buf));
close(fd);
if(ret==-1){
perror("ERROR in rc_pru_stop reading state before stopping");
close(fd);
return -1;
}
if(strcmp(buf,"offline\n")==0){
return 0;
}
else if(strcmp(buf,"running\n")==0){
if(ch==0) fd=open(PRU0_STATE, O_WRONLY);
else fd=open(PRU1_STATE, O_WRONLY);
ret=write(fd,"stop",4);
close(fd);
if(ret==-1){
perror("ERROR in rc_pru_stop while writing to remoteproc state");
return -1;
}
}
else{
fprintf(stderr, "ERROR in rc_pru_stop remoteproc state should be 'offline' or 'running', read:%s\n", buf);
return -1;
}
if(ch==0) fd=open(PRU0_STATE, O_RDONLY);
else fd=open(PRU1_STATE, O_RDONLY);
memset(buf,0,sizeof(buf));
ret=read(fd, buf, sizeof(buf));
close(fd);
if(ret==-1){
perror("ERROR in rc_pru_stop reading state after stopping");
return -1;
}
if(strcmp(buf,"offline\n")){
fprintf(stderr, "ERROR in rc_pru_stop, remoteproc state should now be 'offline', read:%s\n", buf);
return -1;
}
return 0;
}