[3587f7f] | 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 |
|
---|
[f0689d3] | 7 | // C++
|
---|
| 8 | #include <iostream>
|
---|
| 9 |
|
---|
| 10 | // POSIX
|
---|
| 11 | #include <semaphore.h>
|
---|
| 12 | #include <unistd.h>
|
---|
| 13 |
|
---|
| 14 | // Haiku
|
---|
| 15 | #include <USBKit.h>
|
---|
| 16 |
|
---|
[8659a17] | 17 | #include "../shared.h"
|
---|
| 18 | #include "icsp.h"
|
---|
[f0689d3] | 19 |
|
---|
[8659a17] | 20 |
|
---|
| 21 | // We need a subclass of USBRoster to enumerate devices.
|
---|
[f0689d3] | 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 |
|
---|
[8659a17] | 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 | */
|
---|
[f0689d3] | 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;
|
---|
[8659a17] | 48 | // Notify main thread it's ok to continue
|
---|
[f0689d3] | 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 |
|
---|
[3587f7f] | 80 | int main(int argc, char** argv)
|
---|
| 81 | {
|
---|
[f0689d3] | 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 |
|
---|
[8659a17] | 126 | // If we found no valid action request, print usage and exit
|
---|
| 127 | if (action <= 0 || action == 'h')
|
---|
[f0689d3] | 128 | {
|
---|
| 129 | usage(argv[0]);
|
---|
[8659a17] | 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);
|
---|
[f0689d3] | 133 | }
|
---|
| 134 |
|
---|
[3587f7f] | 135 | // TODO handle the boring usb stuff... (might be nice to abstract it so we
|
---|
| 136 | // can use both libusb and haiku usb kit)
|
---|
[f0689d3] | 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;
|
---|
[8659a17] | 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.
|
---|
[f0689d3] | 150 | sem_getvalue(&deviceLock, &deviceAvailable);
|
---|
| 151 | if(deviceAvailable == 0)
|
---|
| 152 | {
|
---|
[8659a17] | 153 | std::cout << "Programmer hardware not detected. Please connect it now..." << std::endl;
|
---|
[f0689d3] | 154 | }
|
---|
| 155 |
|
---|
[8659a17] | 156 | // Wait for the device
|
---|
[f0689d3] | 157 | sem_wait(&deviceLock);
|
---|
| 158 |
|
---|
[8659a17] | 159 | ICSP icsp(*theDevice);
|
---|
| 160 |
|
---|
| 161 | // take action depending on command request in CLI
|
---|
[f0689d3] | 162 | switch(action)
|
---|
| 163 | {
|
---|
| 164 | case 'r':
|
---|
[8659a17] | 165 | // read the chip
|
---|
| 166 | icsp.Read(filename);
|
---|
| 167 | break;
|
---|
[f0689d3] | 168 | case 'w':
|
---|
[8659a17] | 169 | icsp.Write(filename);
|
---|
| 170 | // Here, perform the programming cycle !
|
---|
| 171 | break;
|
---|
[f0689d3] | 172 | case 'e':
|
---|
[8659a17] | 173 | icsp.Erase();
|
---|
| 174 | // erase the chip
|
---|
| 175 | break;
|
---|
[f0689d3] | 176 | }
|
---|
[8659a17] | 177 |
|
---|
| 178 | exit(0);
|
---|
[3587f7f] | 179 | }
|
---|