Master program remake
I spent some time with Spin making the slave0 & master programs, I also spent some time with PropBASIC, now it's time to get back to C.
Below I started to do a C remake of my Spin version of master program. First, I tried to implement the XBee driver code, in C, necessary to get the XBee working. My code seemed to get the XBee working, but I could not get a C version of xbee_driver_Rx() to work. In the C code I tried using fgets, and fgetc with no success. The program below uses a spin2cpp conversion of the Spin code.
I would like to have an explanation for the multiple inits that are necessary for using FILE *term ..., it seems that their should be some way to just initialize it once, and be able to use term in not only main(), but in all the functions(), where it would be necessary. I am still having trouble understanding why, when I have a term running in main(), I can not get another FDS running in do_job1. I am running main() out to a terminal program on pins 25, and 24, but when I try do get do_job1 to use stdout, or use pins 31,and 30, everything falls apart.
The other thing I noticed is that when I initialized FILE *term ..., you have to have both the extern ..., lines of code, and you have to have the _Driver code present. It seems that if you have FullDuplexSerial.c in the compile mix, why do you have to have the extern ..., and _Driver lines of code?
Once I add the filetest.c, and RTC code, I will try to make do_job1 cog behave like my logger cog which I have in the Spin version. That should be fun, I hope it works.
Ray
Below I started to do a C remake of my Spin version of master program. First, I tried to implement the XBee driver code, in C, necessary to get the XBee working. My code seemed to get the XBee working, but I could not get a C version of xbee_driver_Rx() to work. In the C code I tried using fgets, and fgetc with no success. The program below uses a spin2cpp conversion of the Spin code.
I would like to have an explanation for the multiple inits that are necessary for using FILE *term ..., it seems that their should be some way to just initialize it once, and be able to use term in not only main(), but in all the functions(), where it would be necessary. I am still having trouble understanding why, when I have a term running in main(), I can not get another FDS running in do_job1. I am running main() out to a terminal program on pins 25, and 24, but when I try do get do_job1 to use stdout, or use pins 31,and 30, everything falls apart.
The other thing I noticed is that when I initialized FILE *term ..., you have to have both the extern ..., lines of code, and you have to have the _Driver code present. It seems that if you have FullDuplexSerial.c in the compile mix, why do you have to have the extern ..., and _Driver lines of code?
Once I add the filetest.c, and RTC code, I will try to make do_job1 cog behave like my logger cog which I have in the Spin version. That should be fun, I hope it works.
Ray
/**
* @file Master0.c
* This is the main Master0 program start point.
*/
#include <propeller.h>
#include <stdlib.h>
#include <stdio.h>
#include <driver.h>
#include <unistd.h>
extern _Driver _SimpleSerialDriver;
extern _Driver _FullDuplexSerialDriver;
_Driver *_driverlist[] = {
&_SimpleSerialDriver,
&_FullDuplexSerialDriver,
NULL
};
FILE *stdinfile;
FILE *stdoutfile;
volatile int input;
void do_job1(void *arg)
{
stdinfile = stdin;
stdoutfile = stdout;
// FILE *term = fopen("FDS:115200,25,24","r+");
// FILE *stdT = fopen("FDS:115200,31,30","r+");
xbee_driver_Start(27,26,0,9600);
xbee_driver_At_configval("ATMY",0);
// int input;
waitcnt(CLKFREQ + CNT);
// fprintf(stdT,"Slave0 Temp & Humidity\n");
// fflush(stdT);
while(1)
{
// input = xbee_driver_Rx();
// if (input == 0x21) //0x21 '!' char
// {
// fprintf(term,"%c",0xD); //0xD 'CR' carriage return
// fflush(term);
// }
// else
// {
// fprintf(term,"%c",input);
// fflush(term);
// }
// usleep(50);
// fflush(term);
}
}
void high(int WCpin)
{
unsigned int bits = 1 << WCpin;
DIRA |= bits;
OUTA |= bits;
}
void low(int WCpin)
{
unsigned int mask = 1 << WCpin;
DIRA |= mask;
OUTA &= ~mask;
}
void getxb(void)
{
FILE *term = fopen("FDS:115200,25,24","r+");
while(1)
{
input = xbee_driver_Rx();
if (input < 0x21 || input > 0x21)
{
fprintf(term,"%c",input);
continue;
}
else if (input == 0x21)
{
fflush(term);
fprintf(term, "%d\n", 10);
break;
}
}
}
/**
* Main program function.
*/
int main(void)
{
FILE *term = fopen("FDS:115200,25,24","r+");
int stacksize = sizeof(_thread_state_t)+sizeof(int)*3;
int *stack = (int*) malloc(stacksize);
int cog;
cog = cogstart(do_job1, NULL, stack, stacksize);
waitcnt(CLKFREQ + CNT);
fprintf(term,"This is Main\n");
getxb();
while(1)
{
input = xbee_driver_Rx();
if (input == 0x21) //0x21 '!' char
{
fprintf(term,"%c",0xD); //0xD 'CR' carriage return
fflush(term);
}
else
{
fprintf(term,"%c",input);
fflush(term);
}
usleep(50);
fflush(term);
}
return 0;
}

Comments
As for your other question, about the FILE *term, there is a big difference between local variables (ones declared inside a function) and global variables (ones declared outside a function). Local variables can only be accessed inside the function, but global variables can be accessed anywhere. If you want to share the term variable, you have to make the variable global.
Eric
This looks like a big program redesign problem, need help from the experts. Not sure if this can be done, the way I think it should be done, using C and the Propeller. I am not even sure that if there was code refinement that that would even make it fit in CMM mode. So, the biggest problem that I can see is trying to get a cog to run in XMMC mode, in other words to have it work like the program outline below.
I already tried using pthreads, that did not work out. I would need a thread that acted like a cog, which does not work that way. The only other thing that is left, is trying to use a cog_c style, which is way to complex for me to even attempt to try. And in my opinion, probably would not do what I want it to do anyway. So, does my master program have to start looking for a new chip to work with?
Ray
/** * @file Master0.c * This is the main Master0 program start point. */ #include <propeller.h> #include <stdlib.h> #include <stdio.h> #include <driver.h> #include <unistd.h> extern _Driver _SimpleSerialDriver; extern _Driver _FullDuplexSerialDriver; //_Driver *_driverlist[] = { // &_SimpleSerialDriver, // &_FullDuplexSerialDriver, // NULL //}; FILE *stdinfile; FILE *stdoutfile; volatile int input; void do_job1(void *arg) { // stdinfile = stdin; // stdoutfile = stdout; // SW1 = 0; // FILE *term = fopen("FDS:115200,25,24","r+"); // FILE *stdT = fopen("FDS:115200,31,30","r+"); xbee_driver_Start(27,26,0,9600); xbee_driver_At_configval("ATMY",0); // int input; // waitcnt(CLKFREQ + CNT); // fprintf(stdT,"Slave0 Temp & Humidity\n"); // fflush(stdT); while(1) { // input = xbee_driver_Rx(); // if (input == 0x21) //0x21 '!' char // { // fprintf(term,"%c",0xD); //0xD 'CR' carriage return // fflush(term); // } // else // { // fprintf(term,"%c",input); // fflush(term); // } // usleep(50); // fflush(term); } } void high(int WCpin) { unsigned int bits = 1 << WCpin; DIRA |= bits; OUTA |= bits; } void low(int WCpin) { unsigned int mask = 1 << WCpin; DIRA |= mask; OUTA &= ~mask; } void getxb(void) { FILE *term = fopen("FDS:115200,25,24","r+"); while(1) { input = xbee_driver_Rx(); if (input < 0x21 || input > 0x21) { fprintf(term,"%c",input); continue; } else if (input == 0x21) { fflush(term); fprintf(term, "%d\n", 10); break; } } } void continousXB(void) { FILE *term = fopen("FDS:115200,25,24","r+"); while(1) { input = xbee_driver_Rx(); if (input == 0x21) //0x21 '!' char { fprintf(term,"%c",0xD); //0xD 'CR' carriage return fflush(term); } else { fprintf(term,"%c",input); fflush(term); } usleep(50); fflush(term); } } /** * Main program function. */ int main(void) { FILE *term = fopen("FDS:115200,25,24","r+"); int stacksize = sizeof(_thread_state_t)+sizeof(int)*3; int *stack = (int*) malloc(stacksize); int cog; cog = cogstart(do_job1, NULL, stack, stacksize); int num; char *tokens[20]; uint8_t buffer[80]; waitcnt(CLKFREQ + CNT); fprintf(term,"This is Main\n"); // getxb(); while(1) { fprintf(term,"> "); fflush(term); fgets(term,40,buffer); // fscanf(term,"%s",buffer); num = tokenize(buffer, tokens); num = CheckRedirection(tokens, num); if (num == 0) continue; if (!strcmp(tokens[0], "help")) Help(); else if (!strcmp(tokens[0], "quit")) break; else if (!strcmp(tokens[0], "getxb")) getxb(); else { fprintf(term, "Invalid command\n"); } CloseRedirection(); } fprintf(term,"System Stop!\n"); return 0; }Have you tried to check the option to use simple printf or tinylib (in beta only IIRC)? Usually (in the later case) it can shave off easily like 10kb of code.
Also, in more than one place I noticed that you're fopen-ing 'term' with "r+" but then writing to it by fprintf instead. Either I misuderstood something or this is not supposed to work unless a write mode is used. Same with 'stdT'.
-j
I implemented the getxb() command for a test run of the XBee, that seems to be working like expect, but the characters that are being output, is sometimes not the full line that I expect. I think there is a timing issue between the pthreads, but I am not sure.
The other concern that I have is that when one of the pthreads grows in terms of lines of code, will the timing have to be fine tuned to make it work correctly? In do_job1, I have the LED that is flashing at a one second rate, and in do_job2, I have a sleep(1) in the while(1) loop, so they seemed to be balanced, but are not behaving correctly. Any ideas as to how to fix the mentioned problems?
Ray
/** * @file master.c * This is the main master program start point. */ #include <propeller.h> #include <stdio.h> #include <pthread.h> #include <unistd.h> extern _Driver _SimpleSerialDriver; extern _Driver _FullDuplexSerialDriver; //_Driver *_driverlist[] = { // &_SimpleSerialDriver, // &_FullDuplexSerialDriver, // NULL //}; FILE *stdinfile; FILE *stdoutfile; volatile int input; void *do_job1(void *arg) { // FILE *term2 = fopen("FDS:115200,31,30","r+"); pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); xbee_driver_Start(27,26,0,9600); xbee_driver_At_configval("ATMY",0); waitcnt(CLKFREQ + CNT); printf("do_job1 started\n"); while(1) { high(16); usleep(500000); low(16); usleep(500000); //usleep(250); } } void *do_job2(void *arg) { FILE *term2 = fopen("FDS:115200,25,24","r+"); pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); int num; char *tokens[20]; uint8_t buffer[80]; waitcnt(CLKFREQ + CNT); fprintf(term2,"do_job2 started\n"); while(1) { fprintf(term2,"> "); fflush(term2); fscanf(term2,"%s", buffer); num = tokenize(buffer, tokens); num = CheckRedirection(tokens, num); if (num == 0) continue; if (!strcmp(tokens[0], "help")) Help(); else if (!strcmp(tokens[0], "getxb")) getxb(); else { fprintf(term2,"Invalid command\n"); } CloseRedirection(); sleep(1); } } void Help() { FILE *term2 = fopen("FDS:115200,25,24","r+"); fprintf(term2,"Commands are: help, cat, rm, ls, ll, echo, cd, pwd, mkdir\n"); fprintf(term2," rmdir, time, date, setclock, settime, and quit.\n"); } void getxb(void) { FILE *term2 = fopen("FDS:115200,25,24","r+"); while(1) { input = xbee_driver_Rx(); if (input < 0x21 || input > 0x21) { fprintf(term2,"%c",input); fflush(term2); continue; } else if (input == 0x21) { fprintf(term2, "%d\n", 0x10); fflush(term2); break; } } } void high(int WCpin) { unsigned int bits = 1 << WCpin; DIRA |= bits; OUTA |= bits; } void low(int WCpin) { unsigned int mask = 1 << WCpin; DIRA |= mask; OUTA &= ~mask; } pthread_t thr[1]; pthread_t thr1[1]; /** * Main program function. */ int main(int argc, char* argv[]) { // FILE *term = fopen("FDS:115200,25,24","r+"); int i; waitcnt(CLKFREQ + CNT); printf("This is a threaded session\n"); pthread_create(&thr[i], NULL, do_job1, NULL); pthread_create(&thr1[i], NULL, do_job2, NULL); printf("Threads launched\n"); while(1) { usleep(5); } return 0; }Please don't use waitcnt with pthreads. Use usleep instead.
The second thing is, I am using a DNA board, and I have it set with XMMC mode. Now in this program, a FullDuplexSerial.c(spin2cpp) is being implemented via xbee_drive.c(spin2cpp). Since the FullDuplexSerial.c program implements a cog, why is this program still able to run, I thought that cogs did not work in XMMC mode?
I am going in a different direction with this program, I will be creating a C# program that will actually take the data, that will be coming via pins 31,30, and the C# program will manipulate the data, either for display on the screen, or create a CSV file for further manipulation. Also from the C# program, I will try to control things that are running in the pthreads, for example the slave0 xbee that is sending data.
Ray
/** * @file testLEDs.c * This is the main testLEDs program start point. */ #include <propeller.h> #include <pthread.h> #include <stdio.h> extern _Driver _SimpleSerialDriver; extern _Driver _FullDuplexSerialDriver; _Driver *_driverlist[] = { &_SimpleSerialDriver, &_FullDuplexSerialDriver, NULL }; void *do_job1(void *arg) { // FILE *term2 = fopen("FDS:115200,31,30","r+"); high(16); int input; pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job1 started\n"); while(1) { xbee_driver_Rxflush(); while(1) { input = xbee_driver_Rx(); if (input < 0x21 || input > 0x21) { printf("%c",input); fflush(stdout); continue; } else if (input == 0x21) { xbee_driver_Rxflush(); printf("%d\n", 0x10); fflush(stdout); break; } } // high(16); // usleep(500000); // low(16); // usleep(500000); sleep(2); } } void *do_job2(void *arg) { pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job2 started\n"); while(1) { high(17); usleep(400000); low(17); usleep(400000); // usleep(250); } } void *do_job3(void *arg) { pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job3 started\n"); while(1) { high(18); usleep(600000); low(18); usleep(600000); // usleep(250); } } void *do_job4(void *arg) { pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job4 started\n"); while(1) { high(19); usleep(400000); low(19); usleep(400000); // usleep(250); } } void *do_job5(void *arg) { pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job5 started\n"); while(1) { high(20); usleep(500000); low(20); usleep(500000); // usleep(250); } } void *do_job6(void *arg) { pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job6 started\n"); while(1) { high(21); usleep(300000); low(21); usleep(300000); // usleep(250); } } void *do_job7(void *arg) { pthread_set_affinity_thiscog_np(); pthread_detach(pthread_self()); waitcnt(CLKFREQ + CNT); printf("do_job7 started\n"); while(1) { high(22); usleep(500000); low(22); usleep(500000); // usleep(250); } } int high(int WCpin) { unsigned int bits = 1 << WCpin; DIRA |= bits; OUTA |= bits; return 0; } int low(int WCpin) { unsigned int mask = 1 << WCpin; DIRA |= mask; OUTA &= ~mask; return 0; } pthread_t thr[1]; pthread_t thr1[1]; pthread_t thr2[1]; pthread_t thr3[1]; pthread_t thr4[1]; pthread_t thr5[1]; pthread_t thr6[1]; /** * Main program function. */ int main(void) { int i; xbee_driver_Start(27,26,0,9600); xbee_driver_At_configval("ATMY",0); usleep(25); pthread_create(&thr[i], NULL, do_job1, NULL); pthread_create(&thr1[i], NULL, do_job2, NULL); pthread_create(&thr2[i], NULL, do_job3, NULL); pthread_create(&thr3[i], NULL, do_job4, NULL); pthread_create(&thr4[i], NULL, do_job5, NULL); pthread_create(&thr5[i], NULL, do_job6, NULL); pthread_create(&thr6[i], NULL, do_job7, NULL); waitcnt(CLKFREQ + CNT); printf("Main job started\n"); while(1) { usleep(500); } return 0; }Ray
FILE *stdinfile; FILE *stdoutfile; stdinfile = stdin; stdoutfile = stdout; int InChar; waitcnt(CLKFREQ + CNT); printf("Main job started\n"); while(1) { fflush(stdin); InChar = getc(stdin); if (InChar == NULL) continue; if (InChar == '0x100') job2LEDh = 17; InChar = 0; usleep(500); }Ray
void makeraw() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); stdin->_flag &= ~_IOCOOKED; }I now have a simple C# program where I have buttons to control the LED in do_job1, and a button to get a getxb() displayed in the main text window. So far it is all working as expected, but this is the easy stuff.
Ray
/** * @file testCleds.c * This is the main testCogsLEDs program start point. */ #include <propeller.h> #include <pthread.h> #include <stdio.h> extern _Driver _SimpleSerialDriver; extern _Driver _FullDuplexSerialDriver; _Driver *_driverlist[] = { &_SimpleSerialDriver, &_FullDuplexSerialDriver, NULL }; FILE *stdinfile; FILE *stdoutfile; volatile int ledon; volatile int ledoff; void do_job1(void *arg) { while(1) { high(ledon); // usleep(500000); low(ledoff); // usleep(500000); usleep(250); } } void do_job2(void *arg) { // while(1) // { // high(17); // usleep(400000); // low(17); // usleep(400000); usleep(250); // } } void do_job3(void *arg) { while(1) { // high(18); // usleep(600000); // low(18); // usleep(600000); usleep(250); } } void do_job4(void *arg) { while(1) { // high(19); // usleep(300000); // low(19); // usleep(300000); usleep(250); } } void do_job5(void *arg) { while(1) { // high(20); // usleep(500000); // low(20); // usleep(500000); usleep(250); } } void do_job6(void *arg) { while(1) { // high(21); // usleep(400000); // low(21); // usleep(400000); usleep(250); } } void do_job7(void *arg) { while(1) { // high(22); // usleep(600000); // low(22); // usleep(600000); usleep(250); } } int high(int WCpin) { unsigned int bits = 1 << WCpin; DIRA |= bits; OUTA |= bits; return 0; } int low(int WCpin) { unsigned int mask = 1 << WCpin; DIRA |= mask; OUTA &= ~mask; return 0; } void getxb() { int input; // while(1) // { xbee_driver_Rxflush(); while(1) { input = xbee_driver_Rx(); if (input < 0x21 || input > 0x21) { printf("%c",input); fflush(stdout); continue; } else if (input == 0x21) { xbee_driver_Rxflush(); printf("%d\n", 0x10); fflush(stdout); break; } } // } } /** * Main program function. */ int main(void) { stdinfile = stdin; stdoutfile = stdout; int stacksize = sizeof(_thread_state_t)+sizeof(int)*3; int *stack = (int*) malloc(stacksize); int cog; cog = cogstart(do_job1, NULL, stack, stacksize); int stacksize1 = sizeof(_thread_state_t)+sizeof(int)*3; int *stack1 = (int*) malloc(stacksize1); int cog1; cog1 = cogstart(do_job2, NULL, stack1, stacksize1); int stacksize2 = sizeof(_thread_state_t)+sizeof(int)*3; int *stack2 = (int*) malloc(stacksize2); int cog2; cog2 = cogstart(do_job3, NULL, stack2, stacksize2); int stacksize3 = sizeof(_thread_state_t)+sizeof(int)*3; int *stack3 = (int*) malloc(stacksize3); int cog3; cog3 = cogstart(do_job4, NULL, stack3, stacksize3); int stacksize4 = sizeof(_thread_state_t)+sizeof(int)*3; int *stack4 = (int*) malloc(stacksize4); int cog4; cog4 = cogstart(do_job5, NULL, stack4, stacksize4); int stacksize5 = sizeof(_thread_state_t)+sizeof(int)*3; int *stack5 = (int*) malloc(stacksize5); int cog5; cog5 = cogstart(do_job6, NULL, stack5, stacksize5); // When I use XBee, this is no longer available. // int stacksize6 = sizeof(_thread_state_t)+sizeof(int)*3; // int *stack6 = (int*) malloc(stacksize6); // int cog6; // cog6 = cogstart(do_job7, NULL, stack6, stacksize6); xbee_driver_Start(27,26,0,9600); xbee_driver_At_configval("ATMY",0); usleep(25); int InChar; waitcnt(CLKFREQ + CNT); printf("Start of program\n"); while(1) { InChar = getc(stdin); if (InChar == '0') //48 - LED on { ledon = 16; ledoff = 35; } if (InChar == '1') //49 - LED off { ledon = 35; ledoff = 16; } if (InChar == '2') //50 { getxb(); // Get a slice of the streaming data } } return 0; }I tried your code without xbee since I don't have one of those or your xbee c file.
Of course it doesn't work because you didn't follow Dave Hein's suggestion above.
Here is a more flexible version of makeraw() to set echo by the driver.
/** * pass non-zero to the function to make the driver echo characters. */ void makeraw(int echo) { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); if(echo) stdin->_flag |= _IOCOOKED; else stdin->_flag &= ~_IOCOOKED; }If you call it with "makeraw(0);" you would be responsible for echoing the character.
Hope this helps.
--Steve