1 | /* HEREPIC - AVR based ICSP programmer for 16F6xx and 16F8xx chips
|
---|
2 | * Copyright 2012, Adrien Destugues <pulkomandy@gmail.com>
|
---|
3 | *
|
---|
4 | * This file is distributed under the terms of the MIT licence
|
---|
5 | */
|
---|
6 |
|
---|
7 | // C++
|
---|
8 | #include <iostream>
|
---|
9 |
|
---|
10 | // POSIX
|
---|
11 | #include <semaphore.h>
|
---|
12 | #include <unistd.h>
|
---|
13 |
|
---|
14 | // Haiku
|
---|
15 | #include <USBKit.h>
|
---|
16 |
|
---|
17 | #include "../shared.h"
|
---|
18 | #include "icsp.h"
|
---|
19 |
|
---|
20 |
|
---|
21 | // We need a subclass of USBRoster to enumerate devices.
|
---|
22 | class MyUSBRoster: public BUSBRoster {
|
---|
23 | public:
|
---|
24 | MyUSBRoster(BUSBDevice*& device, sem_t& deviceLock)
|
---|
25 | : fDevice(device)
|
---|
26 | , fDeviceLock(deviceLock)
|
---|
27 | {
|
---|
28 | Start();
|
---|
29 | }
|
---|
30 |
|
---|
31 | ~MyUSBRoster()
|
---|
32 | {
|
---|
33 | sem_destroy(&fDeviceLock);
|
---|
34 | Stop();
|
---|
35 | }
|
---|
36 |
|
---|
37 | /* The DeviceAdded hook will be called for all plugged devices.
|
---|
38 | If we don't find the correct one, the method will also be called later,
|
---|
39 | as devices are plugged. So we can wait for the right device to come in!
|
---|
40 | */
|
---|
41 | status_t DeviceAdded(BUSBDevice* device)
|
---|
42 | {
|
---|
43 | if(device->VendorID() == 0x16c0 && device->ProductID() == 0x05DC
|
---|
44 | && strcmp(device->ManufacturerString(), "pulkomandy.tk") == 0
|
---|
45 | && strcmp(device->ProductString(), "HerePic") == 0)
|
---|
46 | {
|
---|
47 | fDevice = device;
|
---|
48 | // Notify main thread it's ok to continue
|
---|
49 | sem_post(&fDeviceLock);
|
---|
50 | }
|
---|
51 | return B_OK;
|
---|
52 | }
|
---|
53 |
|
---|
54 | void DeviceRemoved(BUSBDevice* device)
|
---|
55 | {
|
---|
56 | // TODO send message to main app to tell there's a problem !
|
---|
57 | // or we may even commit suicide at this point...
|
---|
58 | }
|
---|
59 | private:
|
---|
60 | BUSBDevice*& fDevice;
|
---|
61 | sem_t& fDeviceLock;
|
---|
62 | };
|
---|
63 |
|
---|
64 |
|
---|
65 | void usage(const char* progname)
|
---|
66 | {
|
---|
67 | // print usage
|
---|
68 | std::cout << progname << " - AVR based ICSP programmer for "
|
---|
69 | "PIC16F62x and PIC16F87x" << std::endl <<
|
---|
70 | "Written by Adrien Destugues <pulkomandy@gmail.com>"
|
---|
71 | << std::endl << std::endl <<
|
---|
72 | "Usage:" << std::endl <<
|
---|
73 | " -w file.hex Write file to device" << std::endl <<
|
---|
74 | " -r file.hex Read device to file" << std::endl <<
|
---|
75 | " -e Erase device" << std::endl <<
|
---|
76 | " -h Display this help message" << std::endl;
|
---|
77 | }
|
---|
78 |
|
---|
79 |
|
---|
80 | int main(int argc, char** argv)
|
---|
81 | {
|
---|
82 | // parse CLI args
|
---|
83 | static const char* optstring = ":w:r:eh";
|
---|
84 |
|
---|
85 | int nextopt;
|
---|
86 | signed char action = 0;
|
---|
87 | const char* filename;
|
---|
88 |
|
---|
89 | do {
|
---|
90 | nextopt = getopt(argc,argv, optstring);
|
---|
91 |
|
---|
92 | switch(nextopt)
|
---|
93 | {
|
---|
94 | case 'w':
|
---|
95 | case 'r':
|
---|
96 | case 'h':
|
---|
97 | case 'e':
|
---|
98 | // We get the filename in all cases, for h and e it will give
|
---|
99 | // meaningless results but we won't be using it anyway
|
---|
100 | filename = optarg;
|
---|
101 | // store the action, but make sure we do it only once
|
---|
102 | if (action > 0)
|
---|
103 | {
|
---|
104 | std::cerr << "multiple actions specified (only one of w,r,e is allowed)" << std::endl;
|
---|
105 | action = -1;
|
---|
106 | } else {
|
---|
107 | action = nextopt;
|
---|
108 | }
|
---|
109 | break;
|
---|
110 | case ':':
|
---|
111 | std::cout << "option -" << (char)optopt << " needs an argument" << std::endl;
|
---|
112 | break;
|
---|
113 | case '?':
|
---|
114 | std::cerr << "Unknown option: -" << (char)optopt << std::endl;
|
---|
115 | break;
|
---|
116 | case -1:
|
---|
117 | // end of options
|
---|
118 | break;
|
---|
119 | default:
|
---|
120 | std::cerr << "Command-line format error at argument " << optind
|
---|
121 | << std::endl;
|
---|
122 | break;
|
---|
123 | }
|
---|
124 | } while(nextopt != -1);
|
---|
125 |
|
---|
126 | // If we found no valid action request, print usage and exit
|
---|
127 | if (action <= 0 || action == 'h')
|
---|
128 | {
|
---|
129 | usage(argv[0]);
|
---|
130 | // Exit code is EXIT_SUCCESS if we reach this by -h option. Otherwise
|
---|
131 | // the arguments are incorrect
|
---|
132 | exit(action < 0 ? action : 0);
|
---|
133 | }
|
---|
134 |
|
---|
135 | // TODO handle the boring usb stuff... (might be nice to abstract it so we
|
---|
136 | // can use both libusb and haiku usb kit)
|
---|
137 |
|
---|
138 | BUSBDevice* theDevice = NULL;
|
---|
139 | sem_t deviceLock;
|
---|
140 |
|
---|
141 | sem_init(&deviceLock, false, 0);
|
---|
142 |
|
---|
143 | MyUSBRoster usbRoster(theDevice, deviceLock);
|
---|
144 | usbRoster.Start();
|
---|
145 |
|
---|
146 | int deviceAvailable;
|
---|
147 | // TODO we rely on the initial device scan being done when we get here. Is
|
---|
148 | // that always true ? If not, we may print this message in cases where it
|
---|
149 | // is not needed.
|
---|
150 | sem_getvalue(&deviceLock, &deviceAvailable);
|
---|
151 | if(deviceAvailable == 0)
|
---|
152 | {
|
---|
153 | std::cout << "Programmer hardware not detected. Please connect it now..." << std::endl;
|
---|
154 | }
|
---|
155 |
|
---|
156 | // Wait for the device
|
---|
157 | sem_wait(&deviceLock);
|
---|
158 |
|
---|
159 | ICSP icsp(*theDevice);
|
---|
160 |
|
---|
161 | // take action depending on command request in CLI
|
---|
162 | switch(action)
|
---|
163 | {
|
---|
164 | case 'r':
|
---|
165 | // read the chip
|
---|
166 | icsp.Read(filename);
|
---|
167 | break;
|
---|
168 | case 'w':
|
---|
169 | icsp.Write(filename);
|
---|
170 | // Here, perform the programming cycle !
|
---|
171 | break;
|
---|
172 | case 'e':
|
---|
173 | icsp.Erase();
|
---|
174 | // erase the chip
|
---|
175 | break;
|
---|
176 | }
|
---|
177 |
|
---|
178 | exit(0);
|
---|
179 | }
|
---|