//this function sends text to the LCD, with compensation for non-linearity //write a character to the LCD with wrap to the next line void LCD_WriteChar(char c){ HD44780_WriteByte(DATA, c); //wrap the cursor at the end of the line //1-20, line 1, 0x00-0x13 //21-40, line 2, 0x40-0x53 //41-60, line 3, 0x14-0x27 (20) //61-80, line 4, 0x54-0x67 cursorPosition++; if (cursorPosition==21 || cursorPosition==41 || cursorPosition==61){ LCD_CursorPosition(cursorPosition); }else if (cursorPosition==81){ cursorPosition=0; LCD_CursorPosition(cursorPosition); } }
void printPart_lcd() { LCD_Clear(); LCD_CursorPosition(0); LCD_WriteString(type_descs[PartSS]); if(PartSS == ERROR || PartSS >= NOID) return; LCD_WriteINT(part_val); LCD_WriteChar(part_unit); LCD_CursorPosition(21); LCD_WriteString("1:"); LCD_WriteChar(pins[0]); LCD_WriteChar(' '); LCD_WriteString("2:"); LCD_WriteChar(pins[1]); LCD_WriteChar(' '); LCD_WriteString("3:"); LCD_WriteChar(pins[2]); LCD_WriteChar(' '); }
//this function redraws the LCD, takes care of scrolling void LCD_refresh(void){ static unsigned char searchTerm=0; unsigned char i,j,k; if(trendParser.success==0) return; //don't clear the IP address until we successfully connect to terms feed switch(displayMode){ case IDLE: break;//do nothing case UPDATE: //this section draws the basic frame with updating... in the scroll area // // Basic screen layout (all lines) // //clear screen LCD_Clear(); //Write line 1: Trending now: LCD_CursorPosition(1); LCD_WriteString("Trending now:"); //write line 3: LCD_CursorPosition(41); LCD_WriteString(">Recent tweets"); //write line 2/4: updating... LCD_CursorPosition(21); LCD_WriteString(" updating..."); LCD_CursorPosition(61); LCD_WriteString(" updating..."); searchTerm=0;//reset the local searchTerm index variable that tracks which trend term is presently highlighted scrollOffset=0;//clear both scroll offsets scrollOffset2=0; displayMode=IDLE; //next time, the dislay does nothing break; case NEWSCROLL: //this draws the highlighted trend term on line three and continues to the scroll function // // Update current trend (line 3) // LCD_CursorPosition(41); //line 3, position 1 LCD_WriteString(" ");//clear old term LCD_CursorPosition(41); //get the start position of the currently highlighted term //if it's 0, start at 0, else start at the end of the last term+1 i=0; if(searchTerm!=0) i=trendParser.bufValueEndPosition[(searchTerm-1)];//get start postion (already +1 because of auto increment) j=0; k=(trendParser.bufValueEndPosition[searchTerm]-1); //save a few operations if we're not optimizing well while(i<k){ //repeat untill the end positon //<= if(j==20 || i==TREND_PARSER_BUFFER )break; //prevent overruns and line over-writes LCD_WriteChar(trendParser.buf[i]); //write the character fromt he buffer to the LCD i++; j++; } displayMode=SCROLL; //next time just scroll case SCROLL: // // Trend scroll (line 2) // LCD_CursorPosition(21);//line 2 scrollPointer=scrollOffset; //adjust the scroll position based on the previous position for(i=0; i<20; i++){ //draw 20 characters, offset one from the previous time, loop 0 is we hit the end scrollPointer++; if(scrollPointer>=trendParser.bufWritePointer || scrollPointer>=TREND_PARSER_BUFFER ) scrollPointer=0; LCD_WriteChar(trendParser.buf[scrollPointer]); //write the character to the LCD } scrollOffset++; //next time start one positon further in the text buffer if(scrollOffset>=trendParser.bufWritePointer || scrollOffset>= TREND_PARSER_BUFFER){ //reset at the end, prevent overruns scrollOffset=0; } // // Tweet scroll (line 4) // if(searchParser.term!=0){//if at least one trend term is populated, scroll the stored tweets (search results) LCD_CursorPosition(61);//line 4 scrollPointer2=scrollOffset2; //get the offset from last time //j=searchParser.bufValueEndPosition[searchTerm];//store this so it's easier to get each time for(i=0; i<20; i++){ //write 20 characters from the tweet search parser buffer scrollPointer2++; if((scrollPointer2>searchParser.bufValueEndPosition[searchTerm]) || (scrollPointer2>= SEARCH_PARSER_BUFFER)){ if(scrollPointer2<searchParser.bufWritePointer) LCD_WriteChar(searchParser.buf[scrollPointer2]); //display the next character HD44780_WriteByte(DATA, c); else LCD_WriteChar(' ');//lead out the end of the line end with blanks, don't do a partial repeat }else{ LCD_WriteChar(searchParser.buf[scrollPointer2]); //display the next character } } scrollOffset2++;//increment the scroll offset //if we're at the end (10 from the end) or overrun, reset the scroll offset and change the highlighted trend term if((scrollOffset2+10)>=searchParser.bufValueEndPosition[searchTerm] || scrollOffset2>= SEARCH_PARSER_BUFFER){ while(1){ searchTerm++;//next term if(searchTerm==searchParser.term || searchTerm>=MAX_TREND_TERMS){ searchTerm=0; //if more terms than we have fetched, or more than max, go back to 0 scrollOffset2=0;//start at beginning next time break;//get out of this loop if we're starting over! }else{ if(searchParser.bufValueEndPosition[searchTerm]!=0){ scrollOffset2=(searchParser.bufValueEndPosition[(searchTerm-1)]);//get the end postion of the next tweet section scrollOffset2=scrollOffset2-10;//adjust for continous scroll break; //if there's no data for this term, skip it } } } displayMode=NEWSCROLL; //update the currently highlighted term next time before scrolling } }//scroll line 4 break; } }
void twatchTasks(char frameAdvance){ //this state machine services the #twatch static enum _twatchState { TWATCH_INIT=0, TWATCH_IDLE, TWATCH_TRENDS_TCP_START, TWATCH_TRENDS_TCP_SOCKET_OBTAINED, TWATCH_TRENDS_TCP_PROCESS_RESPONSE, TWATCH_TRENDS_TCP_DISCONNECT, TWATCH_SEARCH_TCP_START, TWATCH_SEARCH_TCP_SOCKET_OBTAINED, TWATCH_SEARCH_TCP_PROCESS_RESPONSE, TWATCH_SEARCH_TCP_DISCONNECT, } twatchState = TWATCH_INIT; //massive twitter parsing state machine static enum _HTTPstatus { UNKNOWN=0, OK, ERROR, } HTTPstatus = UNKNOWN; //get and track HTTP status and handle errors static unsigned char HTTPheaderBuf[20]; //used to store HTTP headers static unsigned char HTTPheaderBufCnt; //pointer static BYTE refreshFeeds=0, HTTPretry=0, URLencode[]="%20";//extra static vars for twitter parser BYTE i,k; WORD w; BYTE vBuffer[51]; BYTE cnt; static TICK Timer; static TCP_SOCKET MySocket = INVALID_SOCKET; if(frameAdvance==1) refreshFeeds++; //counts the minutes switch(twatchState) { case TWATCH_INIT: trendParser.success=0; //clear these flag on first run searchParser.success=0;//display IP address and info until valid connection twatchState=TWATCH_TRENDS_TCP_START; //start TCP data grabber next cycle break; case TWATCH_IDLE: //if this variable set, then start the refresh process if(refreshFeeds>TWATCH_REFRESH_INTERVAL){ //if it has been at least 5 minutes, get new trends and tweet search results refreshFeeds=0; HTTPretry=0; //reset the number of retries twatchState=TWATCH_TRENDS_TCP_START; //start TCP data grabber next cycle } break; case TWATCH_TRENDS_TCP_START: //connect to twitter server MySocket = TCPOpen((DWORD)&ServerName[0], TCP_OPEN_RAM_HOST, ServerPort, TCP_PURPOSE_GENERIC_TCP_CLIENT); if(MySocket == INVALID_SOCKET) break; //abort if error, try again next time trendParser.updatingData=1; //updating data flag (probably not used anywhere) displayMode=UPDATE; //next LCD refresh will draw the update screen and then idle twatchState=TWATCH_TRENDS_TCP_SOCKET_OBTAINED; Timer = TickGet(); break; case TWATCH_TRENDS_TCP_SOCKET_OBTAINED: // Wait for the remote server to accept our connection request if(!TCPIsConnected(MySocket)) { // Time out if too much time is spent in this state if(TickGet()-Timer > 5*TICK_SECOND) { // Close the socket so it can be used by other modules TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; twatchState--; } break; } Timer = TickGet(); if(TCPIsPutReady(MySocket) < 125u) break; //if socket error, break and wait //form our trending topics JSON datafeed request TCPPutROMString(MySocket, (ROM BYTE*)"GET "); TCPPutROMString(MySocket, TrendURL); //use the trend URL TCPPutROMString(MySocket, (ROM BYTE*)" HTTP/1.0\r\nHost: "); TCPPutString(MySocket, ServerName); TCPPutROMString(MySocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n"); TCPFlush(MySocket); //send HTTP request to Twitter //setup/clear the parser struct trendParser.bufWritePointer=0; trendParser.foundTag=0; trendParser.tagCharMatchCnt=0; trendParser.tagTotalCnt=0; trendParser.bufWritePointer=0; searchParser.bufWritePointer=0;//reset the tweet buffer write pointer searchParser.term=0; //reset the number of terns in the tweet search parser structure for(i=0; i<MAX_TREND_TERMS; i++) searchParser.bufValueEndPosition[i]=0;//reset all buffer positions to 0 HTTPstatus = UNKNOWN; //reset the http status checker HTTPheaderBufCnt=0; //status checker buffer counter twatchState=TWATCH_TRENDS_TCP_PROCESS_RESPONSE; //next time process any incoming data break; case TWATCH_TRENDS_TCP_PROCESS_RESPONSE: if(!TCPIsConnected(MySocket)) twatchState = TWATCH_TRENDS_TCP_DISCONNECT; //check if we're still connected // Do not break; We might still have data in the TCP RX FIFO waiting for us w = TCPIsGetReady(MySocket);//how many bytes waiting? //process the server reply i = sizeof(vBuffer)-1; vBuffer[i] = '\0'; while(w){ if(w < i){ i = w; vBuffer[i] = '\0'; } w -= TCPGetArray(MySocket, vBuffer, i); for(cnt=0;cnt<i;cnt++){ //---------------// switch(HTTPstatus){ //check the first few bytes for HTTP/1.1 200 OK case UNKNOWN: //cache until a line break, then check header for response code before extracting tags HTTPheaderBuf[HTTPheaderBufCnt]=vBuffer[cnt];//add to the headerbuf array if(HTTPheaderBufCnt<19) HTTPheaderBufCnt++; //if it won't overrun the array, increment the counter if(vBuffer[cnt]==0x0d){//if current character is a line break, examine the header for the response code //is it HTTP? if(HTTPheaderBuf[0]=='H' && HTTPheaderBuf[1]=='T' && HTTPheaderBuf[2]=='T' && HTTPheaderBuf[3]=='P' ){ //loop past /1.x and space HTTPheaderBufCnt=4; while(HTTPheaderBuf[HTTPheaderBufCnt]!=' '){ HTTPheaderBufCnt++; if(HTTPheaderBufCnt>19) break; //buffer overrun } HTTPheaderBufCnt++; //is it 200? (should be a ASCII->int loop that gets the actual value for error handling.... check for overrun if( (HTTPheaderBufCnt <=17 ) && HTTPheaderBuf[HTTPheaderBufCnt]=='2' && HTTPheaderBuf[HTTPheaderBufCnt+1]=='0' && HTTPheaderBuf[HTTPheaderBufCnt+2]=='0'){ HTTPstatus=OK;//200 OK }else{ HTTPstatus=ERROR; //other status, error } } } break; case OK: //HTTP is OK, process the byte procTrend(vBuffer[cnt]); //json parsing state maching break; case ERROR://do nothing because we need to clear the buffer break; } //------------------// }//for loop if(twatchState == TWATCH_TRENDS_TCP_PROCESS_RESPONSE) break; }//while break; case TWATCH_TRENDS_TCP_DISCONNECT: TCPDisconnect(MySocket); //close the socket MySocket = INVALID_SOCKET; //did not get valid HTML, retry, got no tags, retry if(HTTPstatus!=OK || trendParser.tagTotalCnt==0 ){ HTTPretry++; if(HTTPretry>HTTP_MAX_RETRY){//retry 3 times, then wait a minute.... twatchState = TWATCH_IDLE; LCD_CursorPosition(21); //display waiting error LCD_WriteString("*Error, waiting 5min"); break; } LCD_CursorPosition(21); //display retry error LCD_WriteString("*Error, reconnecting"); twatchState = TWATCH_TRENDS_TCP_START; break; } HTTPretry=0; addToTrendBuffer(' ');//add trailing space trendParser.updatingData=0; //data update complete, clear update flag if(trendParser.success==0){ //if this is the first time throuigh, set the success flag trendParser.success=1; //set success flag, used to identify the very first successful xfer and clear IP address screen LCD_refresh(); //clear IP, show update screen } displayMode=NEWSCROLL;//start scrolling the terms, tweets will show when available in the parser struct twatchState = TWATCH_SEARCH_TCP_START; //will start searching on each term next time. searchParser.term set to 0 above... break; case TWATCH_SEARCH_TCP_START: //begins searching for recent tweets for each trending term //don't continue if there's no more term, an error, or overrun if(searchParser.term>=trendParser.tagTotalCnt || searchParser.term>=MAX_TREND_TERMS ){//don't continue if there's no more terms left to search twatchState = TWATCH_IDLE; //go back to idle break; } //skip if 0 length term if(trendParser.bufValueStartPosition[searchParser.term]==trendParser.bufValueEndPosition[searchParser.term]) { searchParser.term++; //increment to next trend term twatchState = TWATCH_SEARCH_TCP_START; //try again with the next trend term break; } //connect to twitter MySocket = TCPOpen((DWORD)&ServerName[0], TCP_OPEN_RAM_HOST, ServerPort, TCP_PURPOSE_GENERIC_TCP_CLIENT); if(MySocket == INVALID_SOCKET) break; //abort on error twatchState=TWATCH_SEARCH_TCP_SOCKET_OBTAINED; Timer = TickGet(); break; case TWATCH_SEARCH_TCP_SOCKET_OBTAINED: // Wait for the remote server to accept our connection request if(!TCPIsConnected(MySocket)){ // Time out if too much time is spent in this state if(TickGet()-Timer > 5*TICK_SECOND){ // Close the socket so it can be used by other modules TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; twatchState--; //searchParser.term++; //increment to next trend term, don't get stuck in loop //should add retries } break; } Timer = TickGet(); if(TCPIsPutReady(MySocket) < 125u) break; //socket ready for writes? TCPPutROMString(MySocket, (ROM BYTE*)"GET "); //setup the HTTP GET request TCPPutROMString(MySocket, SearchURL); //JSON search datafeed URL #ifndef JSON_DEBUG //add the search term to the JSON search URL. Requires urlencoding i=trendParser.bufValueStartPosition[searchParser.term]; //get the starting position of the term in the trend term buffer k=trendParser.bufValueEndPosition[searchParser.term]-1; //end position is one less because of auto increment //add each character of the trend term to the search URL while((i<k) && i<TREND_PARSER_BUFFER ){ //append each byte to the URL until the end position //URLencode anything not a-zA-Z0-9 -_.!~*'() if(URLencodeChar(trendParser.buf[i], &URLencode[0])==0){ TCPPut(MySocket, trendParser.buf[i]); //no URLencode required; }else{ TCPPutString(MySocket, URLencode); //use the URLencoded character now in URLencode array } i++; } #endif //form the rest of the HTTP request TCPPutROMString(MySocket, (ROM BYTE*)" HTTP/1.0\r\nHost: "); TCPPutString(MySocket, ServerName); TCPPutROMString(MySocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n"); TCPFlush(MySocket); //send the HTTP request to the Twitter server //setup the search parser struct searchParser.foundTag=0; searchParser.tagCharMatchCnt=0; searchParser.tagTotalCnt=0; searchParser.escape=0; HTTPstatus = UNKNOWN; //clear the HTTP status checker HTTPheaderBufCnt=0; addToSearchBuffer(0xff); //add beginning block to the text twatchState=TWATCH_SEARCH_TCP_PROCESS_RESPONSE; break; case TWATCH_SEARCH_TCP_PROCESS_RESPONSE: if(!TCPIsConnected(MySocket)) twatchState = TWATCH_SEARCH_TCP_DISCONNECT; //check for connection // Do not break; We might still have data in the TCP RX FIFO waiting for us w = TCPIsGetReady(MySocket); //how many bytes waiting? i = sizeof(vBuffer)-1; vBuffer[i] = '\0'; //add trailing 0 to array. while(w){ //process server reply if(w < i){ i = w; vBuffer[i] = '\0'; } w -= TCPGetArray(MySocket, vBuffer, i); for(cnt=0;cnt<i;cnt++){ //---------------// switch(HTTPstatus){ case UNKNOWN: //check header for response code before extracting tags HTTPheaderBuf[HTTPheaderBufCnt]=vBuffer[cnt];//add to the headerbuf array if(HTTPheaderBufCnt<19) HTTPheaderBufCnt++; //if it won't overrun the array, increment the counter if(vBuffer[cnt]==0x0d){//current character is a line break, examine the header for the response code //is it HTTP? if(HTTPheaderBuf[0]=='H' && HTTPheaderBuf[1]=='T' && HTTPheaderBuf[2]=='T' && HTTPheaderBuf[3]=='P' ){ //loop past /1.x and space HTTPheaderBufCnt=4; while(HTTPheaderBuf[HTTPheaderBufCnt]!=' '){ HTTPheaderBufCnt++; if(HTTPheaderBufCnt>19) break; //buffer overrun } HTTPheaderBufCnt++; //is it 200? (should be a ASCII->int loop that gets the actual value for error handling.... if( ((HTTPheaderBufCnt+2) < 20) && HTTPheaderBuf[HTTPheaderBufCnt]=='2' && HTTPheaderBuf[HTTPheaderBufCnt+1]=='0' && HTTPheaderBuf[HTTPheaderBufCnt+2]=='0'){ HTTPstatus=OK; }else{ HTTPstatus=ERROR; } } } break; case OK: procSearch(vBuffer[cnt]); break; case ERROR://do nothing because we need to clear the buffer break; } //------------------// }//for loop if(twatchState == TWATCH_SEARCH_TCP_PROCESS_RESPONSE) break; }//while break; case TWATCH_SEARCH_TCP_DISCONNECT: TCPDisconnect(MySocket); //close the socket MySocket = INVALID_SOCKET; //did not get valid HTML, retry, got no tags, retry once if no tags if(HTTPstatus!=OK ){ HTTPretry++; if(HTTPretry>HTTP_MAX_RETRY){//retry, then wait till next time... twatchState = TWATCH_IDLE; break; } twatchState = TWATCH_SEARCH_TCP_START; break; } HTTPretry=0; //success, clear number or retries //repeat for each trend term searchParser.success=1; searchParser.term++; twatchState = TWATCH_SEARCH_TCP_START; break; }//switch }//function
void LCD_ExitCGRAM(void){ LCD_CursorPosition(cursorPosition);}
void main(void){ unsigned char i,cmd, param[9], tmp; unsigned long lhfe; //unsigned char t[]={"Hello World"}; init(); //setup the crystal, pins Delay_MS(10); HD44780_Reset();//setup the LCD HD44780_Init(); //LCD_Backlight(1);//turn it on, we ignore the parameter LCD_CursorPosition(0); LCD_WriteString("Part Ninja v0.0a"); LCD_CursorPosition(21); LCD_WriteString(" testing..."); while(1){ PartType=0; PartMode=0; RepeatDetect=0; checkpins(0, 1, 2); //CBE npn -- checkpins(0, 2, 1); //CBE npn checkpins(1, 0, 2); //CBE npn -- checkpins(1, 2, 0); //CBE npn checkpins(2, 0, 1); //CBE npn checkpins(2, 1, 0); //CBE npn if(PartType==PART_TRANSISTOR){ if(RepeatDetect==0){ hfe[1] = hfe[0]; vBE[1] = vBE[0]; } if(hfe[0]>hfe[1]){ hfe[1] = hfe[0]; vBE[1] = vBE[0]; tmp = c; c = e; e = tmp; } lhfe = hfe[1]; lhfe *= (((unsigned long)4700 * 100) / (unsigned long)680); //Verhältnis von High- zu Low-Widerstand if(vBE[1]<11) vBE[1] = 11; lhfe /= vBE[1]; hfe[1] = (unsigned int) lhfe; LCD_Clear(); LCD_CursorPosition(0); if(PartMode == PART_MODE_NPN) { LCD_WriteString("NPN "); } else if (PartMode==PART_MODE_PNP) { LCD_WriteString("PNP "); } LCD_WriteString(" hFE:"); LCD_WriteByteVal(hfe[1]); LCD_CursorPosition(21); LCD_WriteString("C="); LCD_WriteChar(c+0x31); LCD_WriteString(" B="); LCD_WriteChar(b+0x31); LCD_WriteString(" E="); LCD_WriteChar(e+0x31); }else if(PartType==PART_FET){ LCD_Clear(); LCD_CursorPosition(0); if(PartMode == PART_MODE_NPN) { LCD_WriteString("N-"); } else if (PartMode==PART_MODE_PNP) { LCD_WriteString("P-"); } LCD_WriteString("FET "); f=gthvoltage; f=((f)/1024)*5; gthvoltage=f; LCD_WriteString(" Vth:"); LCD_WriteByteVal(gthvoltage); //lcd_data('m'); LCD_WriteString("v"); LCD_CursorPosition(21); LCD_WriteString("G="); LCD_WriteChar(b+0x31); LCD_WriteString(" D="); LCD_WriteChar(c+0x31); LCD_WriteString(" S="); LCD_WriteChar(e+0x31); } } }//end main
void main(void){ unsigned char i,cmd, param[9]; //unsigned char t[]={"Hello World"}; init(); //setup the crystal, pins usbbufflush(); //setup the USB byte buffer delayMS(10); HD44780_Reset();//setup the LCD HD44780_Init(); USBDeviceInit();//setup usb while(1){ USBDeviceTasks(); if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) continue; usbbufservice();//load any USB data into byte buffer cmd=waitforbyte();//wait for a byte from USB if(cmd!=MATRIX_ORBITAL_COMMAND){//assume text, if 254 then enter command mode LCD_WriteChar(cmd); //not a command, just write it to the display }else{//previous byte was 254, now get actual command switch(waitforbyte()){//switch on the command case BACKLIGHT_ON: //1 parameter (minutes 00=forever) param[0]=waitforbyte(); LCD_Backlight(1);//turn it on, we ignore the parameter break; case BACKLIGHT_OFF: LCD_Backlight(0);//backlight off break; case CLEAR: LCD_Clear(); break; case HOME: LCD_Home(); break; case POSITION: //2 parameters (col, row) param[0]=waitforbyte(); param[1]=waitforbyte(); cmd=( ((param[1]-1)*20) + param[0] ); //convert to 20x4 layout (used defined lines, add rows...) LCD_CursorPosition(cmd); break; case UNDERLINE_CURSER_ON: LCD_UnderlineCursor(1); break; case UNDERLINE_CURSER_OFF: LCD_UnderlineCursor(0); break; case BLOCK_CURSER_ON: LCD_BlinkCursor(1); break; case BLOCK_CURSER_OFF: LCD_BlinkCursor(0); break; case BACKLIGHT_BRIGHTNESS://1 parameter (brightness) param[0]=waitforbyte(); break; case CUSTOM_CHARACTER: //9 parameters (character #, 8 byte bitmap) LCD_WriteCGRAM(waitforbyte());//write character address for(i=1; i<9; i++){ LCD_WriteRAM(waitforbyte()); //send 8 bitmap bytes } break; default: //error break; } } CDCTxService(); } }//end main