/*
* op.c - control program for the open programmer
* Copyright (C) 2009-2020 Alberto Maccioni
* for detailed info see:
* http://openprog.altervista.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
* or see <http://www.gnu.org/licenses/>
*/
#include "common.h"
#include "common_functions.h"
#include "I2CSPI.h"
#include "deviceRW.h"
#include "fileIO.h"
#include "progAVR.h"
#if !defined _WIN32 && !defined __CYGWIN__
#include <sys/select.h>
int kbhit()
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0;
tv.tv_usec=0;
FD_ZERO(&read_fd);
FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1) return 0;
if(FD_ISSET(0,&read_fd)) return 1;
return 0;
}
#define getch getchar
#else
#include "conio.h"
#endif
int info=0;
int devType=0x10000;
char dev[64]="";
void msDelay(double delay);
void TestHw();
int StartHVReg(double V);
void DisplayEE();
int FindDevice();
int main (int argc, char **argv) {
int ee=0,r=0,ver=0,c=0,support=0,i2c=0,spi_mode=0,i,j,testhw=0,s1=0;
int spi_speed=0,command=0,langfile=0,help=0;
char lang[32]="";
unsigned char tmpbuf[128];
opterr = 0;
int option_index = 0;
int fuse3k=0;
char* langid=0;
int cw1,cw2,cw3,cw4,cw5,cw6,cw7;
cw1=cw2=cw3=cw4=cw5=cw6=cw7=0x10000;
#if defined _WIN32 || defined __CYGWIN__ //Windows
bufferI=bufferI0+1;
bufferU=bufferU0+1;
bufferI0[0]=0;
bufferU0[0]=0;
#endif
struct option long_options[] =
{
{"BKosccal", no_argument, &load_BKosccal, 1},
{"calib", no_argument, &load_calibword, 1},
{"command", no_argument, &command, 1},
{"cw1", required_argument, 0, '1'},
{"cw2", required_argument, 0, '2'},
{"cw3", required_argument, 0, '3'},
{"cw4", required_argument, 0, '4'},
{"cw5", required_argument, 0, '5'},
{"cw6", required_argument, 0, '6'},
{"cw7", required_argument, 0, '7'},
{"d", required_argument, 0, 'd'},
{"device", required_argument, 0, 'd'},
{"ee", no_argument, &ee, 1},
{"err", required_argument, 0, 'e'},
{"fuse", required_argument, 0, 'f'},
{"fuseh", required_argument, 0, 'F'},
{"fusex", required_argument, 0, 'X'},
{"fuse3k", required_argument, 0, 'k'},
{"h", no_argument, &help,1},
{"help", no_argument, &help,1},
{"HWtest", no_argument, &testhw, 1},
{"info", no_argument, &info, 1},
{"i", no_argument, &info, 1},
{"i2c_r", no_argument, &i2c, 1},
{"i2c_r2", no_argument, &i2c, 2},
{"i2c_w", no_argument, &i2c, 3},
{"i2c_w2", no_argument, &i2c, 4},
{"i2cspeed", required_argument, 0, 'D'},
{"id", no_argument, &programID, 1},
{"icd", required_argument, 0, 'I'},
{"l", optional_argument, 0, 'l'}, //-l=val
{"log", optional_argument, 0, 'l'},
{"lang", required_argument, 0, 'n'},
{"langfile", no_argument, &langfile, 1},
{"lock", required_argument, 0, 'L'},
{"mode", required_argument, 0, 'm'},
{"nolvcheck", no_argument, &skipV33check, 1},
{"osccal", no_argument, &load_osccal, 1},
#if !defined _WIN32 && !defined __CYGWIN__
{"p", required_argument, 0, 'p'},
{"path", required_argument, 0, 'p'},
#endif
{"pid", required_argument, 0, 'P'},
{"rep" , required_argument, 0, 'R'},
{"reserved", no_argument, &r, 1},
{"r", no_argument, &r, 1},
{"s1", no_argument, &s1, 1},
{"S1", no_argument, &s1, 1},
{"s", required_argument, 0, 's'},
{"save", required_argument, 0, 's'},
{"saveEE", required_argument, 0, 'S'},
{"se", required_argument, 0, 'S'},
{"spi_r", no_argument, &i2c, 5},
{"spi_w", no_argument, &i2c, 6},
{"spispeed", required_argument, 0, 'D'},
{"support", no_argument, &support, 1},
{"use_BKosccal", no_argument, &use_BKosccal, 1},
{"version", no_argument, &ver, 1},
{"v", no_argument, &ver, 1},
{"vid", required_argument, 0, 'V'},
{"w", required_argument, 0, 'w'},
{"write", required_argument, 0, 'w'},
{"we", required_argument, 0, 'W'},
{"writeEE", required_argument, 0, 'W'},
{0, 0, 0, 0}
};
while ((c = getopt_long_only (argc, argv, "",long_options,&option_index)) != -1)
/*{ printf("optarg=%X\n",optarg);
if(optarg) printf("%s\n",optarg);
printf("c=%X %c\noption_index=%d name=%s\n",c,c,option_index,long_options[option_index].name); }
exit(0);*/
switch (c)
{
case '1': //force config word 1
i=sscanf(optarg, "%x", &cw1);
if(i!=1||cw1<0||cw1>0x3FFF) cw1=0x10000;
break;
case '2': //force config word 2
i=sscanf(optarg, "%x", &cw2);
if(i!=1||cw2<0||cw2>0x3FFF) cw2=0x10000;
break;
case '3': //force config word 3
i=sscanf(optarg, "%x", &cw3);
if(i!=1||cw3<0||cw3>0x3FFF) cw3=0x10000;
break;
case '4': //force config word 4
i=sscanf(optarg, "%x", &cw4);
if(i!=1||cw4<0||cw4>0x3FFF) cw4=0x10000;
break;
case '5': //force config word 5
i=sscanf(optarg, "%x", &cw5);
if(i!=1||cw5<0||cw5>0x3FFF) cw5=0x10000;
break;
case '6': //force config word 6
i=sscanf(optarg, "%x", &cw6);
if(i!=1||cw6<0||cw6>0x3FFF) cw6=0x10000;
break;
case '7': //force config word 7
i=sscanf(optarg, "%x", &cw7);
if(i!=1||cw7<0||cw7>0x3FFF) cw7=0x10000;
break;
case 'd': //device
strncpy(dev,optarg,sizeof(dev)-1);
break;
case 'e': //max write errors
max_err = atoi(optarg);
break;
case 'D': //spi speed
spi_speed = atoi(optarg);
if(spi_speed<0)spi_speed=0;
if(spi_speed>3)spi_speed=3;
break;
case 'f': //Atmel FUSE low
i=sscanf(optarg, "%x", &AVRfuse);
if(i!=1||AVRfuse<0||AVRfuse>0xFF) AVRfuse=0x100;
break;
case 'F': //Atmel FUSE high
i=sscanf(optarg, "%x", &AVRfuse_h);
if(i!=1||AVRfuse_h<0||AVRfuse_h>0xFF) AVRfuse_h=0x100;
break;
case 'I': //ICD routine address
i=sscanf(optarg, "%x", &ICDaddr);
if(i!=1||ICDaddr<0||ICDaddr>0xFFFF) ICDaddr=0x1F00;
ICDenable=1;
break;
case 'k': //Atmel FUSE low @ 3kHz
i=sscanf(optarg, "%x", &AVRfuse);
if(i!=1||AVRfuse<0||AVRfuse>0xFF) AVRfuse=0x100;
else fuse3k=1;
break;
case 'l': //save Log
saveLog=1;
if(optarg) strncpy(LogFileName,optarg,sizeof(LogFileName));
break;
case 'L': //Atmel LOCK
i=sscanf(optarg, "%x", &AVRlock);
if(i!=1||AVRlock<0||AVRlock>0xFF) AVRlock=0x100;
break;
case 'm': //SPI mode
spi_mode = atoi(optarg);
if(spi_mode<0) spi_mode=0;
if(spi_mode>3) spi_mode=3;
break;
case 'n': //language
strncpy(lang,optarg,sizeof(lang)-1);
break;
#if !defined _WIN32 && !defined __CYGWIN__
case 'p': //hiddev path
strncpy(path,optarg,sizeof(path)-1);
break;
#endif
case 'P': //pid
sscanf(optarg, "%x", &pid);
break;
case 'R': //USB HID report size
//DIMBUF = atoi(optarg);
break;
case 's': //save
strncpy(savefile,optarg,sizeof(savefile)-1);
break;
case 'S': //save EE
strncpy(savefileEE,optarg,sizeof(savefileEE)-1);
break;
case 'V': //vid
sscanf(optarg, "%x", &vid);
break;
case 'X': //Atmel extended FUSE
i=sscanf(optarg, "%x", &AVRfuse_x);
if(i!=1||AVRfuse_x<0||AVRfuse_x>0xFF) AVRfuse_x=0x100;
break;
case 'w': //write file
strncpy(loadfile,optarg,sizeof(loadfile)-1);
break;
case 'W': //write EE file
strncpy(loadfileEE,optarg,sizeof(loadfileEE)-1);
break;
case '?':
fprintf (stderr,strings[L_OPTERR]); //errore opzioni
return 1;
default:
break;
}
for(j=0,i = optind; i < argc&&i<128; i++,j++) sscanf(argv[i], "%x", &tmpbuf[j]);
for(;j<128;j++) tmpbuf[j]=0;
strinit();
i=0;
if(lang[0]){ //explicit language selection
if(lang[0]=='i'&&langid[1]=='t'){ //built-in
strings=strings_it;
i=1;
}
else if(lang[0]=='e'&&lang[1]=='n'){ //built-in
strings=strings_en;
i=1;
}
else i=strfind(lang,"languages.rc"); //file look-up
}
if(i==0){
#if defined _WIN32
langid=malloc(19);
int n=GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SISO639LANGNAME,langid,9);
langid[n-1] = '-';
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SISO3166CTRYNAME,langid+n, 9);
//printf("%d >%s<\n",n,langid);
#else
langid=getenv("LANG");
#endif
if(langid){
if(langid[0]=='i'&&langid[1]=='t') strings=strings_it;
else if(langid[0]=='e'&&langid[1]=='n') strings=strings_en;
else if(strfind(langid,"languages.rc")); //first try full code
else { //then only first language code
char* p=strchr(langid,'-');
if(p) *p=0;
if(!strfind(langid,"languages.rc")) strings=strings_en;
}
}
else strings=strings_en;
}
strncpy(LogFileName,strings[S_LogFile],sizeof(LogFileName));
if(argc==1){
printf("OP v%s\n",VERSION);
printf(strings[L_HELP]);
exit(1);
}
if(help){
printf(strings[L_HELP]);
return 1;
}
if(langfile) GenerateLangFile(langid,"languages.rc");
if (ver){
printf("OP v%s\nCopyright (C) Alberto Maccioni 2009-2023\
\n For detailed info see http://openprog.altervista.org/\
\nThis program is free software; you can redistribute it and/or modify it under \
the terms of the GNU General Public License as published by the Free Software \
Foundation; either version 2 of the License, or (at your option) any later version.\
\n",VERSION);
return 0;
}
if (support){
char list[20000]; //make sure list is long enough!!
AddDevices(list);
printf("%s\n",list);
return 0;
}
DeviceDetected=FindDevice(vid,pid); //connect to USB programmer
if(!DeviceDetected){
DeviceDetected=FindDevice(new_vid,new_pid); //try default
if(DeviceDetected){
vid=new_vid;
pid=new_pid;
}
}
if(!DeviceDetected) DeviceDetected=FindDevice(old_vid,old_pid); //try old one
if(!DeviceDetected) exit(1);
ProgID(); //get firmware version and reset
#if !defined _WIN32 && !defined __CYGWIN__
if(info){
#ifndef hiddevIO //use raw USB device
struct hidraw_devinfo device_info;
char name[256],path[256];
ioctl(fd, HIDIOCGRAWINFO, &device_info);
ioctl(fd, HIDIOCGRAWNAME(256), name);
ioctl(fd, HIDIOCGRAWPHYS(256), path);
printf("VID 0x%04X PID 0x%04X\n",device_info.vendor, device_info.product);
printf(strings[L_NAME], path, name);//"The device on %s says its name is %s\n"
#else //use hiddev device (old method)
struct hiddev_devinfo device_info;
ioctl(fd, HIDIOCGDEVINFO, &device_info);
printf(strings[L_INFO1],device_info.vendor, device_info.product, device_info.version);
printf(strings[L_INFO2],device_info.busnum, device_info.devnum, device_info.ifnum);
char name[256];
strcpy(name,strings[L_UNKNOWN]);//"Unknown"
if(ioctl(fd, HIDIOCGNAME(sizeof(name)), name) < 0) perror("evdev ioctl");
printf(strings[L_NAME], path, name);//"The device on %s says its name is %s\n"
#endif
return 0;
}
#endif
DWORD t0,t;
t=t0=GetTickCount();
if(testhw){
TestHw();
return 0;
}
if(command){
//bufferU[0]=0;
for(i=0;i<DIMBUF;i++) bufferU[i]=(char) tmpbuf[i];
PacketIO(100);
printf("> ");
for(i=0;i<DIMBUF;i++) printf("%02X ",bufferU[i]);
printf("\n< ");
for(i=0;i<DIMBUF;i++) printf("%02X ",bufferI[i]);
printf("\n");
return 0;
}
#define CS 8
#define HLD 16
if(i2c){ //I2C, SPI
if(i2c==1){ //I2C receive 8 bit mode
I2CReceive(0,spi_speed,tmpbuf[0],tmpbuf+1);
}
else if(i2c==2){ //I2C receive 16 bit mode
I2CReceive(1,spi_speed,tmpbuf[0],tmpbuf+1);
}
else if(i2c==3){ //I2C transmit 8 bit mode
I2CSend(0,spi_speed,tmpbuf[0],tmpbuf+1);
}
else if(i2c==4){ //I2C transmit 16 bit mode
I2CSend(1,spi_speed,tmpbuf[0],tmpbuf+1);
}
else if(i2c==5){ //SPI receive
I2CReceive(2+spi_mode,spi_speed,tmpbuf[0],tmpbuf+1);
}
else if(i2c==6){ //SPI receive
I2CSend(2+spi_mode,spi_speed,tmpbuf[0],tmpbuf+1);
}
return 0 ;
}
struct DevInfo info;
info=GetDevInfo(dev);
devType=info.family;
if(fuse3k){ //write fuse low @ 3kHz
if(AVRfuse<0x100) WriteATfuseSlow(AVRfuse);
return 0;
}
if(loadfile[0]){ //write
if(Load(dev,loadfile)==-1){
PrintMessage(strings[S_NoCode2]);
PrintMessage("\n");
exit(-1);
}
if(!strncmp(dev,"AT",2)&&loadfileEE[0]) LoadEE(dev,loadfileEE);
//force config words
if(devType==PIC16){
if((!strncmp(dev,"16F1",4)||!strncmp(dev,"12F1",4))&&sizeW>0x8008){ //16F1xxx
if(cw1<=0x3FFF){
memCODE_W[0x8007]=cw1;
PrintMessage3(strings[S_ForceConfigWx],1,0x8007,cw1); //"forcing config word%d [0x%04X]=0x%04X"
}
if(cw2<=0x3FFF){
memCODE_W[0x8008]=cw2;
PrintMessage3(strings[S_ForceConfigWx],2,0x8008,cw2); //"forcing config word%d [0x%04X]=0x%04X"
}
}
else{ //16Fxxx
if(cw1<=0x3FFF&&sizeW>0x2007){
memCODE_W[0x2007]=cw1;
PrintMessage3(strings[S_ForceConfigWx],1,0x2007,cw1); //"forcing config word%d [0x%04X]=0x%04X"
}
if(cw2<=0x3FFF&&sizeW>0x2008){
memCODE_W[0x2008]=cw2;
printf("2\n");
PrintMessage3(strings[S_ForceConfigWx],2,0x2008,cw2); //"forcing config word%d [0x%04X]=0x%04X"
}
}
}
else if(devType==PIC12){ //12Fxxx
if(cw1<=0xFFF&&sizeW>0xFFF){
memCODE_W[0xFFF]=cw1;
PrintMessage3(strings[S_ForceConfigWx],1,0xFFF,cw1); //"forcing config word%d [0x%04X]=0x%04X"
}
}
else if(devType==PIC18){ //18Fxxx
if(cw1<=0xFFFF){
memCONFIG[0]=cw1&0xFF;
memCONFIG[1]=(cw1>>8)&0xFF;
}
if(cw2<=0xFFFF){
memCONFIG[2]=cw2&0xFF;
memCONFIG[3]=(cw2>>8)&0xFF;
}
if(cw3<=0xFFFF){
memCONFIG[4]=cw3&0xFF;
memCONFIG[5]=(cw3>>8)&0xFF;
}
if(cw4<=0xFFFF){
memCONFIG[6]=cw4&0xFF;
memCONFIG[7]=(cw4>>8)&0xFF;
}
if(cw5<=0xFFFF){
memCONFIG[8]=cw5&0xFF;
memCONFIG[9]=(cw5>>8)&0xFF;
}
if(cw6<=0xFFFF){
memCONFIG[10]=cw6&0xFF;
memCONFIG[11]=(cw6>>8)&0xFF;
}
if(cw7<=0xFFFF){
memCONFIG[12]=cw7&0xFF;
memCONFIG[13]=(cw7>>8)&0xFF;
}
PrintMessage(strings[S_ForceConfigW]); //"forcing config words"
for(i=0;i<7;i++){
PrintMessage2(strings[S_ConfigWordH],i+1,memCONFIG[i*2+1]); //"CONFIG%dH: 0x%02X\t"
PrintMessage2(strings[S_ConfigWordL],i+1,memCONFIG[i*2]); //"CONFIG%dL: 0x%02X\r\n"
}
}
/* if(CW1_force!=-1||CW2_force!=-1){
if((!strncmp(dev,"16F1",4)||!strncmp(dev,"12F1",4))){ //16F1xxx
if(CW1_force!=-1&&sizeW>0x8007) memCODE_W[0x8007]=CW1_force;
if(CW2_force!=-1&&sizeW>0x8008) memCODE_W[0x8008]=CW2_force;
}
else if((!strncmp(dev,"16F",3)||!strncmp(dev,"12F6",4))&&strncmp(dev,"16F5",4)){ //16Fxxx
if(CW1_force!=-1&&sizeW>0x2007) memCODE_W[0x2007]=CW1_force;
if(CW2_force!=-1&&sizeW>0x2008) memCODE_W[0x2008]=CW2_force;
}
else if((!strncmp(dev,"12F",3)||!strncmp(dev,"10F",3)||!strncmp(dev,"16F5",4))){ //12Fxxx
if(CW1_force!=-1&&sizeW>0xFFF) memCODE_W[0xFFF]=CW1_force&0xFFF;
}
if(CW1_force!=-1) PrintMessage1(strings[S_ForceConfigWx],CW1_force); //"forcing config word1 (0x%04X)"
if(CW2_force!=-1) PrintMessage1(strings[S_ForceConfigWx],CW2_force); //"forcing config word2 (0x%04X)"
}
*/
//Start with button
if(s1){
PrintMessage(strings[S_WaitS1W]); //"Press S1 to program, any key to exit"
fflush(stdout);
for(;!kbhit();msDelay(50)){
if(CheckS1()){ //wait for S1
Write(dev,ee); //choose the right function
PrintMessage(strings[S_WaitS1W]); //"Press S1 to program, any key to exit"
fflush(stdout);
for(;CheckS1();msDelay(50)); //wait for S1 open
}
}
getch();
}
else Write(dev,ee); //choose the right function
}
else{ //read
if(s1){
PrintMessage(strings[S_WaitS1R]); //"Press S1 to read, any key to exit"
fflush(stdout);
for(;!kbhit();msDelay(50)){
if(CheckS1()){ //wait for S1
Read(dev,ee,r); //choose the right function
PrintMessage(strings[S_WaitS1R]); //"Press S1 to read, any key to exit"
fflush(stdout);
for(;CheckS1();msDelay(50)); //wait for S1 open
}
}
getch();
}
else Read(dev,ee,r); //choose the right function
if(savefile[0]) Save(dev,savefile);
if(!strncmp(dev,"AT",2)&&savefileEE[0]) SaveEE(dev,savefileEE);
}
#if !defined _WIN32 && !defined __CYGWIN__ //Linux
close(fd);
#endif
return 0 ;
}
///
///Display contents of EEprom memory
void DisplayEE(){
char s[256],t[256],v[256];
int valid=0,empty=1;
int i,j;
s[0]=0;
v[0]=0;
PrintMessage(strings[S_EEMem]); //"\r\nmemoria EEPROM:\r\n"
for(i=0;i<sizeEE;i+=COL){
valid=0;
for(j=i;j<i+COL&&j<sizeEE;j++){
sprintf(t,"%02X ",memEE[j]);
strcat(s,t);
sprintf(t,"%c",isprint(memEE[j])?memEE[j]:'.');
strcat(v,t);
if(memEE[j]<0xff) valid=1;
}
if(valid){
PrintMessage3("%04X: %s %s\r\n",i,s,v);
empty=0;
}
s[0]=0;
v[0]=0;
}
if(empty) PrintMessage(strings[S_Empty]); //empty
}