├── .gitattributes
├── .gitignore
├── LICENSE
├── MinerControl.sln
├── MinerControl
├── AlgorithmEntry.cs
├── App.config
├── Extensions.cs
├── Hardware
│ ├── NVAPI.cs
│ └── PInvokeDelegateFactory.cs
├── MainWindow.Designer.cs
├── MainWindow.cs
├── MainWindow.resx
├── MinerControl.conf
├── MinerControl.csproj
├── MiningEngine.cs
├── MiningModeEnum.cs
├── PriceEntries
│ ├── HamsterPoolPriceEntry.cs
│ ├── LtcRabbitPriceEntry.cs
│ ├── ManualPriceEntry.cs
│ ├── NiceHashPriceEntry.cs
│ ├── PriceEntryBase.cs
│ ├── TradeMyBitPriceEntry.cs
│ ├── WafflePoolPriceEntry.cs
│ ├── WePayBtcPriceEntry.cs
│ └── YaampPriceEntry.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── ServiceEnum.cs
├── Services
│ ├── HamsterPoolService.cs
│ ├── IService.cs
│ ├── LtcRabbitService.cs
│ ├── ManualService.cs
│ ├── NiceHashService.cs
│ ├── NiceHashServiceBase.cs
│ ├── ServiceBase.cs
│ ├── TradeMyBitService.cs
│ ├── WafflePoolService.cs
│ ├── WePayBtcService.cs
│ ├── WestHashService.cs
│ └── YaampService.cs
├── Utility
│ ├── ErrorLogger.cs
│ ├── Multicast
│ │ ├── MulticastDataReceivedEventArgs.cs
│ │ ├── MulticastReceiver.cs
│ │ └── MulticastSender.cs
│ ├── ProcessUtil.cs
│ ├── PropertyChangedBase.cs
│ ├── SlidingBuffer.cs
│ ├── SortableBindingList.cs
│ └── WebUtil.cs
├── bitcoin.ico
└── test-run.bat
├── README.md
└── TestMiner
├── App.config
├── Program.cs
├── Properties
└── AssemblyInfo.cs
└── TestMiner.csproj
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | [Bb]in/
16 | [Oo]bj/
17 |
18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
19 | !packages/*/build/
20 |
21 | # MSTest test Results
22 | [Tt]est[Rr]esult*/
23 | [Bb]uild[Ll]og.*
24 |
25 | *_i.c
26 | *_p.c
27 | *.ilk
28 | *.meta
29 | *.obj
30 | *.pch
31 | *.pdb
32 | *.pgc
33 | *.pgd
34 | *.rsp
35 | *.sbr
36 | *.tlb
37 | *.tli
38 | *.tlh
39 | *.tmp
40 | *.tmp_proj
41 | *.log
42 | *.vspscc
43 | *.vssscc
44 | .builds
45 | *.pidb
46 | *.log
47 | *.scc
48 |
49 | # Visual C++ cache files
50 | ipch/
51 | *.aps
52 | *.ncb
53 | *.opensdf
54 | *.sdf
55 | *.cachefile
56 |
57 | # Visual Studio profiler
58 | *.psess
59 | *.vsp
60 | *.vspx
61 |
62 | # Guidance Automation Toolkit
63 | *.gpState
64 |
65 | # ReSharper is a .NET coding add-in
66 | _ReSharper*/
67 | *.[Rr]e[Ss]harper
68 |
69 | # TeamCity is a build add-in
70 | _TeamCity*
71 |
72 | # DotCover is a Code Coverage Tool
73 | *.dotCover
74 |
75 | # NCrunch
76 | *.ncrunch*
77 | .*crunch*.local.xml
78 |
79 | # Installshield output folder
80 | [Ee]xpress/
81 |
82 | # DocProject is a documentation generator add-in
83 | DocProject/buildhelp/
84 | DocProject/Help/*.HxT
85 | DocProject/Help/*.HxC
86 | DocProject/Help/*.hhc
87 | DocProject/Help/*.hhk
88 | DocProject/Help/*.hhp
89 | DocProject/Help/Html2
90 | DocProject/Help/html
91 |
92 | # Click-Once directory
93 | publish/
94 |
95 | # Publish Web Output
96 | *.Publish.xml
97 |
98 | # NuGet Packages Directory
99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
100 | #packages/
101 |
102 | # Windows Azure Build Output
103 | csx
104 | *.build.csdef
105 |
106 | # Windows Store app package directory
107 | AppPackages/
108 |
109 | # Others
110 | sql/
111 | *.Cache
112 | ClientBin/
113 | [Ss]tyle[Cc]op.*
114 | ~$*
115 | *~
116 | *.dbmdl
117 | *.[Pp]ublish.xml
118 | *.pfx
119 | *.publishsettings
120 |
121 | # RIA/Silverlight projects
122 | Generated_Code/
123 |
124 | # Backup & report files from converting an old project file to a newer
125 | # Visual Studio version. Backup files are not needed, because we have git ;-)
126 | _UpgradeReport_Files/
127 | Backup*/
128 | UpgradeLog*.XML
129 | UpgradeLog*.htm
130 |
131 | # SQL Server files
132 | App_Data/*.mdf
133 | App_Data/*.ldf
134 |
135 |
136 | #LightSwitch generated files
137 | GeneratedArtifacts/
138 | _Pvt_Extensions/
139 | ModelManifest.xml
140 |
141 | # =========================
142 | # Windows detritus
143 | # =========================
144 |
145 | # Windows image file caches
146 | Thumbs.db
147 | ehthumbs.db
148 |
149 | # Folder config file
150 | Desktop.ini
151 |
152 | # Recycle Bin used on file shares
153 | $RECYCLE.BIN/
154 |
155 | # Mac desktop service store files
156 | .DS_Store
157 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/MinerControl.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30501.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinerControl", "MinerControl\MinerControl.csproj", "{94CC3F87-4215-4F3F-9524-695BF16FEBD0}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestMiner", "TestMiner\TestMiner.csproj", "{63721D21-B76A-40AE-9A37-0C6F392CEE63}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {94CC3F87-4215-4F3F-9524-695BF16FEBD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {94CC3F87-4215-4F3F-9524-695BF16FEBD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {94CC3F87-4215-4F3F-9524-695BF16FEBD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {94CC3F87-4215-4F3F-9524-695BF16FEBD0}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {63721D21-B76A-40AE-9A37-0C6F392CEE63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {63721D21-B76A-40AE-9A37-0C6F392CEE63}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {63721D21-B76A-40AE-9A37-0C6F392CEE63}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {63721D21-B76A-40AE-9A37-0C6F392CEE63}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/MinerControl/AlgorithmEntry.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MinerControl
3 | {
4 | public class AlgorithmEntry
5 | {
6 | public string Name { get; set; }
7 | public string Display { get; set; }
8 | public decimal Hashrate { get; set; }
9 | public decimal Power { get; set; }
10 |
11 | public string Param1 { get; set; }
12 | public string Param2 { get; set; }
13 | public string Param3 { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MinerControl/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MinerControl/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace MinerControl
8 | {
9 | public static class Extensions
10 | {
11 | public static string FormatTime(this TimeSpan timeSpan, bool zeroAsEmpty = false)
12 | {
13 | if (timeSpan == TimeSpan.Zero && zeroAsEmpty)
14 | return string.Empty;
15 |
16 | return timeSpan.TotalDays > 1
17 | ? timeSpan.ToString(@"dd\.hh\:mm\:ss")
18 | : timeSpan.ToString(@"hh\:mm\:ss");
19 | }
20 |
21 | public static string FormatTime(this TimeSpan? timeSpan)
22 | {
23 | if (!timeSpan.HasValue)
24 | return string.Empty;
25 |
26 | return timeSpan.Value.FormatTime();
27 | }
28 |
29 | public static void AddRange(this IList list, IEnumerable items)
30 | {
31 | foreach (var item in items)
32 | list.Add(item);
33 | }
34 |
35 | public static decimal ExtractDecimal(this object raw)
36 | {
37 | var decimalValue = raw as decimal?;
38 | if (decimalValue.HasValue) return decimalValue.Value;
39 |
40 | var doubleValue = raw as double?;
41 | if (doubleValue.HasValue) return (decimal)doubleValue.Value;
42 |
43 | var floatValue = raw as float?;
44 | if (floatValue.HasValue) return (decimal)floatValue.Value;
45 |
46 | var longValue = raw as long?;
47 | if (longValue.HasValue) return (decimal)longValue.Value;
48 |
49 | var intValue = raw as int?;
50 | if (intValue.HasValue) return (decimal)intValue.Value;
51 |
52 | decimal parseValue;
53 | var style = NumberStyles.AllowDecimalPoint;
54 | var culture = CultureInfo.CreateSpecificCulture("en-US");
55 |
56 | if (decimal.TryParse(raw.ToString(), style, culture, out parseValue)) return parseValue;
57 |
58 | return 0;
59 | }
60 |
61 | public static string GetString(this IDictionary data, string key)
62 | {
63 | if (!data.ContainsKey(key)) return null;
64 | return data[key] as string;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/MinerControl/Hardware/NVAPI.cs:
--------------------------------------------------------------------------------
1 | //http://open-hardware-monitor.googlecode.com/svn/trunk/Hardware/
2 |
3 | /*
4 |
5 | This Source Code Form is subject to the terms of the Mozilla Public
6 | License, v. 2.0. If a copy of the MPL was not distributed with this
7 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | Copyright (C) 2009-2012 Michael Möller
10 | Copyright (C) 2011 Christian Vallières
11 |
12 | */
13 |
14 | using System;
15 | using System.Runtime.InteropServices;
16 | using System.Text;
17 |
18 | namespace OpenHardwareMonitor.Hardware.Nvidia
19 | {
20 |
21 | internal enum NvStatus
22 | {
23 | OK = 0,
24 | ERROR = -1,
25 | LIBRARY_NOT_FOUND = -2,
26 | NO_IMPLEMENTATION = -3,
27 | API_NOT_INTIALIZED = -4,
28 | INVALID_ARGUMENT = -5,
29 | NVIDIA_DEVICE_NOT_FOUND = -6,
30 | END_ENUMERATION = -7,
31 | INVALID_HANDLE = -8,
32 | INCOMPATIBLE_STRUCT_VERSION = -9,
33 | HANDLE_INVALIDATED = -10,
34 | OPENGL_CONTEXT_NOT_CURRENT = -11,
35 | NO_GL_EXPERT = -12,
36 | INSTRUMENTATION_DISABLED = -13,
37 | EXPECTED_LOGICAL_GPU_HANDLE = -100,
38 | EXPECTED_PHYSICAL_GPU_HANDLE = -101,
39 | EXPECTED_DISPLAY_HANDLE = -102,
40 | INVALID_COMBINATION = -103,
41 | NOT_SUPPORTED = -104,
42 | PORTID_NOT_FOUND = -105,
43 | EXPECTED_UNATTACHED_DISPLAY_HANDLE = -106,
44 | INVALID_PERF_LEVEL = -107,
45 | DEVICE_BUSY = -108,
46 | NV_PERSIST_FILE_NOT_FOUND = -109,
47 | PERSIST_DATA_NOT_FOUND = -110,
48 | EXPECTED_TV_DISPLAY = -111,
49 | EXPECTED_TV_DISPLAY_ON_DCONNECTOR = -112,
50 | NO_ACTIVE_SLI_TOPOLOGY = -113,
51 | SLI_RENDERING_MODE_NOTALLOWED = -114,
52 | EXPECTED_DIGITAL_FLAT_PANEL = -115,
53 | ARGUMENT_EXCEED_MAX_SIZE = -116,
54 | DEVICE_SWITCHING_NOT_ALLOWED = -117,
55 | TESTING_CLOCKS_NOT_SUPPORTED = -118,
56 | UNKNOWN_UNDERSCAN_CONFIG = -119,
57 | TIMEOUT_RECONFIGURING_GPU_TOPO = -120,
58 | DATA_NOT_FOUND = -121,
59 | EXPECTED_ANALOG_DISPLAY = -122,
60 | NO_VIDLINK = -123,
61 | REQUIRES_REBOOT = -124,
62 | INVALID_HYBRID_MODE = -125,
63 | MIXED_TARGET_TYPES = -126,
64 | SYSWOW64_NOT_SUPPORTED = -127,
65 | IMPLICIT_SET_GPU_TOPOLOGY_CHANGE_NOT_ALLOWED = -128,
66 | REQUEST_USER_TO_CLOSE_NON_MIGRATABLE_APPS = -129,
67 | OUT_OF_MEMORY = -130,
68 | WAS_STILL_DRAWING = -131,
69 | FILE_NOT_FOUND = -132,
70 | TOO_MANY_UNIQUE_STATE_OBJECTS = -133,
71 | INVALID_CALL = -134,
72 | D3D10_1_LIBRARY_NOT_FOUND = -135,
73 | FUNCTION_NOT_FOUND = -136
74 | }
75 |
76 | internal enum NvThermalController
77 | {
78 | NONE = 0,
79 | GPU_INTERNAL,
80 | ADM1032,
81 | MAX6649,
82 | MAX1617,
83 | LM99,
84 | LM89,
85 | LM64,
86 | ADT7473,
87 | SBMAX6649,
88 | VBIOSEVT,
89 | OS,
90 | UNKNOWN = -1,
91 | }
92 |
93 | internal enum NvThermalTarget
94 | {
95 | NONE = 0,
96 | GPU = 1,
97 | MEMORY = 2,
98 | POWER_SUPPLY = 4,
99 | BOARD = 8,
100 | ALL = 15,
101 | UNKNOWN = -1
102 | };
103 |
104 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
105 | internal struct NvSensor
106 | {
107 | public NvThermalController Controller;
108 | public uint DefaultMinTemp;
109 | public uint DefaultMaxTemp;
110 | public uint CurrentTemp;
111 | public NvThermalTarget Target;
112 | }
113 |
114 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
115 | internal struct NvGPUThermalSettings
116 | {
117 | public uint Version;
118 | public uint Count;
119 | [MarshalAs(UnmanagedType.ByValArray,
120 | SizeConst = NVAPI.MAX_THERMAL_SENSORS_PER_GPU)]
121 | public NvSensor[] Sensor;
122 | }
123 |
124 | [StructLayout(LayoutKind.Sequential)]
125 | internal struct NvDisplayHandle
126 | {
127 | private readonly IntPtr ptr;
128 | }
129 |
130 | [StructLayout(LayoutKind.Sequential)]
131 | internal struct NvPhysicalGpuHandle
132 | {
133 | private readonly IntPtr ptr;
134 | }
135 |
136 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
137 | internal struct NvClocks
138 | {
139 | public uint Version;
140 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_CLOCKS_PER_GPU)]
141 | public uint[] Clock;
142 | }
143 |
144 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
145 | internal struct NvPState
146 | {
147 | public bool Present;
148 | public int Percentage;
149 | }
150 |
151 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
152 | internal struct NvPStates
153 | {
154 | public uint Version;
155 | public uint Flags;
156 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_PSTATES_PER_GPU)]
157 | public NvPState[] PStates;
158 | }
159 |
160 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
161 | internal struct NvUsages
162 | {
163 | public uint Version;
164 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_USAGES_PER_GPU)]
165 | public uint[] Usage;
166 | }
167 |
168 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
169 | internal struct NvCooler
170 | {
171 | public int Type;
172 | public int Controller;
173 | public int DefaultMin;
174 | public int DefaultMax;
175 | public int CurrentMin;
176 | public int CurrentMax;
177 | public int CurrentLevel;
178 | public int DefaultPolicy;
179 | public int CurrentPolicy;
180 | public int Target;
181 | public int ControlType;
182 | public int Active;
183 | }
184 |
185 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
186 | internal struct NvGPUCoolerSettings
187 | {
188 | public uint Version;
189 | public uint Count;
190 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_COOLER_PER_GPU)]
191 | public NvCooler[] Cooler;
192 | }
193 |
194 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
195 | internal struct NvLevel
196 | {
197 | public int Level;
198 | public int Policy;
199 | }
200 |
201 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
202 | internal struct NvGPUCoolerLevels
203 | {
204 | public uint Version;
205 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_COOLER_PER_GPU)]
206 | public NvLevel[] Levels;
207 | }
208 |
209 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
210 | internal struct NvMemoryInfo
211 | {
212 | public uint Version;
213 | [MarshalAs(UnmanagedType.ByValArray, SizeConst =
214 | NVAPI.MAX_MEMORY_VALUES_PER_GPU)]
215 | public uint[] Values;
216 | }
217 |
218 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
219 | internal struct NvDisplayDriverVersion
220 | {
221 | public uint Version;
222 | public uint DriverVersion;
223 | public uint BldChangeListNum;
224 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NVAPI.SHORT_STRING_MAX)]
225 | public string BuildBranch;
226 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NVAPI.SHORT_STRING_MAX)]
227 | public string Adapter;
228 | }
229 |
230 | internal class NVAPI
231 | {
232 |
233 | public const int MAX_PHYSICAL_GPUS = 64;
234 | public const int SHORT_STRING_MAX = 64;
235 |
236 | public const int MAX_THERMAL_SENSORS_PER_GPU = 3;
237 | public const int MAX_CLOCKS_PER_GPU = 0x120;
238 | public const int MAX_PSTATES_PER_GPU = 8;
239 | public const int MAX_USAGES_PER_GPU = 33;
240 | public const int MAX_COOLER_PER_GPU = 20;
241 | public const int MAX_MEMORY_VALUES_PER_GPU = 5;
242 |
243 | public static readonly uint GPU_THERMAL_SETTINGS_VER = (uint)
244 | Marshal.SizeOf(typeof(NvGPUThermalSettings)) | 0x10000;
245 | public static readonly uint GPU_CLOCKS_VER = (uint)
246 | Marshal.SizeOf(typeof(NvClocks)) | 0x20000;
247 | public static readonly uint GPU_PSTATES_VER = (uint)
248 | Marshal.SizeOf(typeof(NvPStates)) | 0x10000;
249 | public static readonly uint GPU_USAGES_VER = (uint)
250 | Marshal.SizeOf(typeof(NvUsages)) | 0x10000;
251 | public static readonly uint GPU_COOLER_SETTINGS_VER = (uint)
252 | Marshal.SizeOf(typeof(NvGPUCoolerSettings)) | 0x20000;
253 | public static readonly uint GPU_MEMORY_INFO_VER = (uint)
254 | Marshal.SizeOf(typeof(NvMemoryInfo)) | 0x20000;
255 | public static readonly uint DISPLAY_DRIVER_VERSION_VER = (uint)
256 | Marshal.SizeOf(typeof(NvDisplayDriverVersion)) | 0x10000;
257 | public static readonly uint GPU_COOLER_LEVELS_VER = (uint)
258 | Marshal.SizeOf(typeof(NvGPUCoolerLevels)) | 0x10000;
259 |
260 | private delegate IntPtr nvapi_QueryInterfaceDelegate(uint id);
261 | private delegate NvStatus NvAPI_InitializeDelegate();
262 | private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(
263 | NvPhysicalGpuHandle gpuHandle, StringBuilder name);
264 |
265 | public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(
266 | NvPhysicalGpuHandle gpuHandle, int sensorIndex,
267 | ref NvGPUThermalSettings nvGPUThermalSettings);
268 | public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum,
269 | ref NvDisplayHandle displayHandle);
270 | public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(
271 | NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles,
272 | out uint gpuCount);
273 | public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate(
274 | [Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);
275 | public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(
276 | NvPhysicalGpuHandle gpuHandle, out int value);
277 | public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(
278 | NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks);
279 | public delegate NvStatus NvAPI_GPU_GetPStatesDelegate(
280 | NvPhysicalGpuHandle gpuHandle, ref NvPStates nvPStates);
281 | public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(
282 | NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages);
283 | public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(
284 | NvPhysicalGpuHandle gpuHandle, int coolerIndex,
285 | ref NvGPUCoolerSettings nvGPUCoolerSettings);
286 | public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(
287 | NvPhysicalGpuHandle gpuHandle, int coolerIndex,
288 | ref NvGPUCoolerLevels NvGPUCoolerLevels);
289 | public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(
290 | NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo);
291 | public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(
292 | NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion
293 | nvDisplayDriverVersion);
294 | public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(
295 | StringBuilder version);
296 | public delegate NvStatus NvAPI_GPU_GetPCIIdentifiersDelegate(
297 | NvPhysicalGpuHandle gpuHandle, out uint deviceId, out uint subSystemId,
298 | out uint revisionId, out uint extDeviceId);
299 |
300 | private static readonly bool available;
301 | private static readonly nvapi_QueryInterfaceDelegate nvapi_QueryInterface;
302 | private static readonly NvAPI_InitializeDelegate NvAPI_Initialize;
303 | private static readonly NvAPI_GPU_GetFullNameDelegate
304 | _NvAPI_GPU_GetFullName;
305 | private static readonly NvAPI_GetInterfaceVersionStringDelegate
306 | _NvAPI_GetInterfaceVersionString;
307 |
308 | public static readonly NvAPI_GPU_GetThermalSettingsDelegate
309 | NvAPI_GPU_GetThermalSettings;
310 | public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate
311 | NvAPI_EnumNvidiaDisplayHandle;
312 | public static readonly NvAPI_GetPhysicalGPUsFromDisplayDelegate
313 | NvAPI_GetPhysicalGPUsFromDisplay;
314 | public static readonly NvAPI_EnumPhysicalGPUsDelegate
315 | NvAPI_EnumPhysicalGPUs;
316 | public static readonly NvAPI_GPU_GetTachReadingDelegate
317 | NvAPI_GPU_GetTachReading;
318 | public static readonly NvAPI_GPU_GetAllClocksDelegate
319 | NvAPI_GPU_GetAllClocks;
320 | public static readonly NvAPI_GPU_GetPStatesDelegate
321 | NvAPI_GPU_GetPStates;
322 | public static readonly NvAPI_GPU_GetUsagesDelegate
323 | NvAPI_GPU_GetUsages;
324 | public static readonly NvAPI_GPU_GetCoolerSettingsDelegate
325 | NvAPI_GPU_GetCoolerSettings;
326 | public static readonly NvAPI_GPU_SetCoolerLevelsDelegate
327 | NvAPI_GPU_SetCoolerLevels;
328 | public static readonly NvAPI_GPU_GetMemoryInfoDelegate
329 | NvAPI_GPU_GetMemoryInfo;
330 | public static readonly NvAPI_GetDisplayDriverVersionDelegate
331 | NvAPI_GetDisplayDriverVersion;
332 | public static readonly NvAPI_GPU_GetPCIIdentifiersDelegate
333 | NvAPI_GPU_GetPCIIdentifiers;
334 |
335 | private NVAPI() { }
336 |
337 | public static NvStatus NvAPI_GPU_GetFullName(NvPhysicalGpuHandle gpuHandle,
338 | out string name)
339 | {
340 | StringBuilder builder = new StringBuilder(SHORT_STRING_MAX);
341 | NvStatus status;
342 | if (_NvAPI_GPU_GetFullName != null)
343 | status = _NvAPI_GPU_GetFullName(gpuHandle, builder);
344 | else
345 | status = NvStatus.FUNCTION_NOT_FOUND;
346 | name = builder.ToString();
347 | return status;
348 | }
349 |
350 | public static NvStatus NvAPI_GetInterfaceVersionString(out string version)
351 | {
352 | StringBuilder builder = new StringBuilder(SHORT_STRING_MAX);
353 | NvStatus status;
354 | if (_NvAPI_GetInterfaceVersionString != null)
355 | status = _NvAPI_GetInterfaceVersionString(builder);
356 | else
357 | status = NvStatus.FUNCTION_NOT_FOUND;
358 | version = builder.ToString();
359 | return status;
360 | }
361 |
362 | private static string GetDllName()
363 | {
364 | if (IntPtr.Size == 4)
365 | {
366 | return "nvapi.dll";
367 | }
368 | else
369 | {
370 | return "nvapi64.dll";
371 | }
372 | }
373 |
374 | private static void GetDelegate(uint id, out T newDelegate)
375 | where T : class
376 | {
377 | IntPtr ptr = nvapi_QueryInterface(id);
378 | if (ptr != IntPtr.Zero)
379 | {
380 | newDelegate =
381 | Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
382 | }
383 | else
384 | {
385 | newDelegate = null;
386 | }
387 | }
388 |
389 | static NVAPI()
390 | {
391 | DllImportAttribute attribute = new DllImportAttribute(GetDllName());
392 | attribute.CallingConvention = CallingConvention.Cdecl;
393 | attribute.PreserveSig = true;
394 | attribute.EntryPoint = "nvapi_QueryInterface";
395 | PInvokeDelegateFactory.CreateDelegate(attribute,
396 | out nvapi_QueryInterface);
397 |
398 | try
399 | {
400 | GetDelegate(0x0150E828, out NvAPI_Initialize);
401 | }
402 | catch (DllNotFoundException) { return; }
403 | catch (EntryPointNotFoundException) { return; }
404 | catch (ArgumentNullException) { return; }
405 |
406 | if (NvAPI_Initialize() == NvStatus.OK)
407 | {
408 | GetDelegate(0xE3640A56, out NvAPI_GPU_GetThermalSettings);
409 | GetDelegate(0xCEEE8E9F, out _NvAPI_GPU_GetFullName);
410 | GetDelegate(0x9ABDD40D, out NvAPI_EnumNvidiaDisplayHandle);
411 | GetDelegate(0x34EF9506, out NvAPI_GetPhysicalGPUsFromDisplay);
412 | GetDelegate(0xE5AC921F, out NvAPI_EnumPhysicalGPUs);
413 | GetDelegate(0x5F608315, out NvAPI_GPU_GetTachReading);
414 | GetDelegate(0x1BD69F49, out NvAPI_GPU_GetAllClocks);
415 | GetDelegate(0x60DED2ED, out NvAPI_GPU_GetPStates);
416 | GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages);
417 | GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings);
418 | GetDelegate(0x891FA0AE, out NvAPI_GPU_SetCoolerLevels);
419 | GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo);
420 | GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion);
421 | GetDelegate(0x01053FA5, out _NvAPI_GetInterfaceVersionString);
422 | GetDelegate(0x2DDFB66E, out NvAPI_GPU_GetPCIIdentifiers);
423 |
424 | available = true;
425 | }
426 | }
427 |
428 | public static bool IsAvailable
429 | {
430 | get { return available; }
431 | }
432 |
433 | }
434 | }
435 |
--------------------------------------------------------------------------------
/MinerControl/Hardware/PInvokeDelegateFactory.cs:
--------------------------------------------------------------------------------
1 | // http://open-hardware-monitor.googlecode.com/svn/trunk/Hardware/
2 |
3 | /*
4 |
5 | This Source Code Form is subject to the terms of the Mozilla Public
6 | License, v. 2.0. If a copy of the MPL was not distributed with this
7 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | Copyright (C) 2009-2012 Michael Möller
10 |
11 | */
12 |
13 | using System;
14 | using System.Collections.Generic;
15 | using System.Reflection;
16 | using System.Reflection.Emit;
17 | using System.Runtime.InteropServices;
18 | //using OpenHardwareMonitor.Collections;
19 |
20 | namespace OpenHardwareMonitor.Hardware
21 | {
22 |
23 | internal static class PInvokeDelegateFactory
24 | {
25 |
26 | private static readonly ModuleBuilder moduleBuilder =
27 | AppDomain.CurrentDomain.DefineDynamicAssembly(
28 | new AssemblyName("PInvokeDelegateFactoryInternalAssembly"),
29 | AssemblyBuilderAccess.Run).DefineDynamicModule(
30 | "PInvokeDelegateFactoryInternalModule");
31 |
32 | //private static readonly IDictionary, Type> wrapperTypes =
33 | // new Dictionary, Type>();
34 | private static readonly IDictionary, Type> wrapperTypes =
35 | new Dictionary, Type>();
36 |
37 | public static void CreateDelegate(DllImportAttribute dllImportAttribute,
38 | out T newDelegate) where T : class
39 | {
40 | Type wrapperType;
41 | //Pair key =
42 | // new Pair(dllImportAttribute, typeof(T));
43 | Tuple key =
44 | new Tuple(dllImportAttribute, typeof(T));
45 | wrapperTypes.TryGetValue(key, out wrapperType);
46 |
47 | if (wrapperType == null)
48 | {
49 | wrapperType = CreateWrapperType(typeof(T), dllImportAttribute);
50 | wrapperTypes.Add(key, wrapperType);
51 | }
52 |
53 | newDelegate = Delegate.CreateDelegate(typeof(T), wrapperType,
54 | dllImportAttribute.EntryPoint) as T;
55 | }
56 |
57 |
58 | private static Type CreateWrapperType(Type delegateType,
59 | DllImportAttribute dllImportAttribute)
60 | {
61 |
62 | TypeBuilder typeBuilder = moduleBuilder.DefineType(
63 | "PInvokeDelegateFactoryInternalWrapperType" + wrapperTypes.Count);
64 |
65 | MethodInfo methodInfo = delegateType.GetMethod("Invoke");
66 |
67 | ParameterInfo[] parameterInfos = methodInfo.GetParameters();
68 | int parameterCount = parameterInfos.GetLength(0);
69 |
70 | Type[] parameterTypes = new Type[parameterCount];
71 | for (int i = 0; i < parameterCount; i++)
72 | parameterTypes[i] = parameterInfos[i].ParameterType;
73 |
74 | MethodBuilder methodBuilder = typeBuilder.DefinePInvokeMethod(
75 | dllImportAttribute.EntryPoint, dllImportAttribute.Value,
76 | MethodAttributes.Public | MethodAttributes.Static |
77 | MethodAttributes.PinvokeImpl, CallingConventions.Standard,
78 | methodInfo.ReturnType, parameterTypes,
79 | dllImportAttribute.CallingConvention,
80 | dllImportAttribute.CharSet);
81 |
82 | foreach (ParameterInfo parameterInfo in parameterInfos)
83 | methodBuilder.DefineParameter(parameterInfo.Position + 1,
84 | parameterInfo.Attributes, parameterInfo.Name);
85 |
86 | if (dllImportAttribute.PreserveSig)
87 | methodBuilder.SetImplementationFlags(MethodImplAttributes.PreserveSig);
88 |
89 | return typeBuilder.CreateType();
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/MinerControl/MainWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Reflection;
8 | using System.Windows.Forms;
9 | using MinerControl.PriceEntries;
10 | using MinerControl.Services;
11 | using MinerControl.Utility;
12 |
13 | namespace MinerControl
14 | {
15 | public partial class MainWindow : Form
16 | {
17 | private MiningEngine _engine = new MiningEngine();
18 | private DateTime AppStartTime = DateTime.Now;
19 |
20 | private bool IsMinimizedToTray
21 | {
22 | get { return _engine.TrayMode > 0 && this.WindowState == FormWindowState.Minimized; }
23 | }
24 |
25 | public MainWindow()
26 | {
27 | _engine.WriteConsoleAction = WriteConsole;
28 | _engine.WriteRemoteAction = WriteRemote;
29 |
30 | InitializeComponent();
31 | }
32 |
33 | private void MainWindow_Load(object sender, EventArgs e)
34 | {
35 | if (!_engine.LoadConfig())
36 | this.Close();
37 | if (!string.IsNullOrWhiteSpace(_engine.CurrencyCode))
38 | _engine.LoadExchangeRates();
39 | }
40 |
41 | private void MainWindow_Shown(object sender, EventArgs e)
42 | {
43 | // speeds up data grid view performance.
44 | typeof(DataGridView).InvokeMember("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, dgPrices, new object[] { true });
45 | typeof(DataGridView).InvokeMember("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, dgServices, new object[] { true });
46 |
47 | dgServices.AutoGenerateColumns = false;
48 | dgServices.DataSource = new SortableBindingList(_engine.Services);
49 |
50 | dgPrices.AutoGenerateColumns = false;
51 | dgPrices.DataSource = new SortableBindingList(_engine.PriceEntries);
52 |
53 | if (!_engine.DoDonationMinging)
54 | {
55 | textDonationStart.Enabled = false;
56 | textDonationEnd.Enabled = false;
57 | }
58 |
59 | lblCurrencySymbol.Text = string.Empty; // Avoid flashing template value when starting
60 |
61 | if (!_engine.RemoteReceive)
62 | tabPage.TabPages.Remove(tabRemote);
63 |
64 | UpdateButtons();
65 | RunCycle();
66 | UpdateGrid(true);
67 |
68 | if (Program.MinimizeOnStart)
69 | MinimizeWindow();
70 |
71 | tmrPriceCheck.Enabled = true;
72 | if (!string.IsNullOrWhiteSpace(_engine.CurrencyCode))
73 | tmrExchangeUpdate.Enabled = true;
74 | if (Program.HasAutoStart)
75 | {
76 | _engine.MiningMode = MiningModeEnum.Automatic;
77 | UpdateButtons();
78 | RunBestAlgo();
79 | }
80 | }
81 |
82 | private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
83 | {
84 | _engine.Cleanup();
85 | }
86 |
87 | #region Timer events
88 |
89 | private void tmrPriceCheck_Tick(object sender, EventArgs e)
90 | {
91 | RunCycle();
92 | UpdateGrid();
93 | }
94 |
95 | private void tmrExchangeUpdate_Tick(object sender, EventArgs e)
96 | {
97 | _engine.LoadExchangeRates();
98 | }
99 |
100 | private void tmrTimeUpdate_Tick(object sender, EventArgs e)
101 | {
102 | UpdateTimes();
103 |
104 | if (_engine.PricesUpdated)
105 | {
106 | UpdateGrid();
107 | _engine.PricesUpdated = false;
108 | }
109 |
110 | var autoModes = new[] { MiningModeEnum.Automatic, MiningModeEnum.Donation };
111 | if (!autoModes.Contains(_engine.MiningMode)) return;
112 |
113 | RunBestAlgo();
114 | }
115 |
116 | #endregion
117 |
118 | private void RunCycle()
119 | {
120 | _engine.CheckPrices();
121 | }
122 |
123 | private void RunBestAlgo()
124 | {
125 | if (!_engine.HasPrices || (Program.HasAutoStart && (DateTime.Now - AppStartTime).TotalSeconds < 3)) return;
126 |
127 | var oldCurrent = _engine.CurrentRunning;
128 | var oldNext = _engine.NextRun;
129 | _engine.RunBestAlgo(IsMinimizedToTray);
130 | if (_engine.CurrentRunning != oldCurrent || _engine.NextRun != oldNext)
131 | UpdateGrid();
132 | }
133 |
134 | private void UpdateButtons()
135 | {
136 | btnStart.Enabled = _engine.MiningMode == MiningModeEnum.Stopped;
137 | btnStop.Enabled = _engine.MiningMode != MiningModeEnum.Stopped;
138 | dgPrices.Columns[dgPrices.Columns.Count - 2].Visible = _engine.MiningMode != MiningModeEnum.Stopped; // Status column
139 | dgPrices.Columns[dgPrices.Columns.Count - 1].Visible = _engine.MiningMode == MiningModeEnum.Stopped; // Action column
140 | }
141 |
142 | private void UpdateGrid(bool forceReorder = false)
143 | {
144 | lock (_engine)
145 | {
146 | // mode 2 == sort always, mode 1 == sort when running, mode 0 == sort never
147 | if (_engine.GridSortMode == 2 || (_engine.GridSortMode == 1 && (forceReorder || _engine.MiningMode == MiningModeEnum.Automatic)))
148 | {
149 | dgPrices.Sort(dgPrices.Columns["NetEarn"], ListSortDirection.Descending);
150 | }
151 | }
152 | }
153 |
154 | #region Buttons
155 |
156 | private void btnStart_Click(object sender, EventArgs e)
157 | {
158 | if (_engine.MiningMode != MiningModeEnum.Stopped) return;
159 | _engine.MiningMode = MiningModeEnum.Automatic;
160 |
161 | UpdateButtons();
162 | RunBestAlgo();
163 | UpdateGrid();
164 | }
165 |
166 | private void btnStop_Click(object sender, EventArgs e)
167 | {
168 | if (_engine.MiningMode == MiningModeEnum.Stopped) return;
169 | _engine.MiningMode = MiningModeEnum.Stopped;
170 |
171 | UpdateButtons();
172 | _engine.RequestStop();
173 | UpdateGrid();
174 | }
175 |
176 | private void dgPrices_CellContentClick(object sender, DataGridViewCellEventArgs e)
177 | {
178 | if (_engine.MiningMode != MiningModeEnum.Stopped) return;
179 |
180 | var senderGrid = (DataGridView)sender;
181 |
182 | if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn && e.RowIndex >= 0)
183 | {
184 | var data = senderGrid.DataSource as IList;
185 | var entry = data[e.RowIndex];
186 |
187 | _engine.MiningMode = MiningModeEnum.Manual;
188 | UpdateButtons();
189 | _engine.RequestStart(entry.Id, IsMinimizedToTray);
190 | UpdateGrid();
191 | }
192 | }
193 |
194 | #endregion
195 |
196 | private void linkDonate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
197 | {
198 | Process.Start("https://blockchain.info/address/1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y");
199 | }
200 |
201 | #region Show/hide window
202 |
203 | private void MinimizeWindow()
204 | {
205 | if (_engine.TrayMode == 0)
206 | {
207 | this.WindowState = FormWindowState.Minimized;
208 | }
209 | else
210 | {
211 | HideWindow();
212 | }
213 | }
214 |
215 | private void HideWindow()
216 | {
217 | notifyIcon.Visible = true;
218 | notifyIcon.ShowBalloonTip(500);
219 | this.Hide();
220 |
221 | _engine.HideMinerWindow();
222 | }
223 |
224 | private void notifyIcon_DoubleClick(object sender, EventArgs e)
225 | {
226 | notifyIcon.Visible = false;
227 | this.Show();
228 | this.WindowState = FormWindowState.Normal;
229 |
230 | _engine.MinimizeMinerWindow();
231 | }
232 |
233 | private void MainWindow_Resize(object sender, EventArgs e)
234 | {
235 | if (_engine.TrayMode > 0 && this.WindowState == FormWindowState.Minimized)
236 | {
237 | HideWindow();
238 | }
239 | }
240 |
241 | #endregion
242 |
243 | private void UpdateTimes()
244 | {
245 | textRunningTotal.Text = _engine.TotalTime.FormatTime();
246 | textTimeCurrent.Text = _engine.MiningTime.FormatTime();
247 | textTimeSwitch.Text = _engine.NextRunTime.FormatTime();
248 | textTimeRestart.Text = _engine.RestartTime.FormatTime();
249 | textDonationStart.Text = _engine.TimeUntilDonation.FormatTime();
250 | textDonationEnd.Text = _engine.TimeDuringDonation.FormatTime();
251 | textCurrencyExchange.Text = _engine.Exchange.ToString("N2");
252 | lblCurrencySymbol.Text = _engine.CurrencySymbol;
253 | if (_engine.Services != null)
254 | {
255 | var balance = _engine.Services.Select(o => o.Currency).Sum();
256 | textCurrencyBalance.Text = balance.ToString("N4");
257 | }
258 | }
259 |
260 | private string ActiveTime(PriceEntryBase priceEntry)
261 | {
262 | var time = priceEntry.TimeMining;
263 | if (_engine.CurrentRunning == priceEntry.Id && _engine.StartMining.HasValue)
264 | time += (DateTime.Now - _engine.StartMining.Value);
265 | return time.FormatTime();
266 | }
267 |
268 | SlidingBuffer _consoleBuffer = new SlidingBuffer(200);
269 |
270 | private void WriteConsole(string text)
271 | {
272 | Invoke(new MethodInvoker(
273 | delegate
274 | {
275 | _consoleBuffer.Add(text);
276 |
277 | textConsole.Lines = _consoleBuffer.ToArray();
278 | textConsole.Focus();
279 | textConsole.SelectionStart = textConsole.Text.Length;
280 | textConsole.SelectionLength = 0;
281 | textConsole.ScrollToCaret();
282 | textConsole.Refresh();
283 | }
284 | ));
285 | }
286 |
287 | SlidingBuffer _remoteBuffer = new SlidingBuffer(200);
288 |
289 | private void WriteRemote(IPAddress source, string text)
290 | {
291 | Invoke(new MethodInvoker(
292 | delegate
293 | {
294 | _remoteBuffer.Add(string.Format("[{0}] {1}", source, text));
295 |
296 | textRemote.Lines = _remoteBuffer.ToArray();
297 | textRemote.Focus();
298 | textRemote.SelectionStart = textRemote.Text.Length;
299 | textRemote.SelectionLength = 0;
300 | textRemote.ScrollToCaret();
301 | textRemote.Refresh();
302 | }
303 | ));
304 | }
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/MinerControl/MinerControl.conf:
--------------------------------------------------------------------------------
1 | {
2 | "general": {
3 | "power": 0.10,
4 | "exchange": 500,
5 | "currencycode": "USD",
6 | "mintime": 4,
7 | "maxtime": 30,
8 | "switchtime": 3,
9 | "deadtime": 10,
10 | "logerrors": true,
11 | "logactivity": true,
12 | "gridsortmode": 1,
13 | "minerkillmode": 1,
14 | "traymode": 1,
15 | "donationpercentage": 2,
16 | "donationfrequency": 240,
17 | "remotesend": true,
18 | "remotereceive": true
19 | },
20 | "algorithms": [
21 | { "name": "x11", "display": "X11", "hashrate": 5860, "power": 49, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a x11" },
22 | { "name": "x13", "display": "X13", "hashrate": 4700, "power": 49, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a x13" },
23 | { "name": "x14", "display": "X14", "hashrate": 4573, "power": 52, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a x14" },
24 | { "name": "x15", "display": "X15", "hashrate": 4097, "power": 52, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a x15" },
25 | { "name": "quark", "display": "Quark", "hashrate": 10548, "power": 54, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a quark" },
26 | { "name": "nist5", "display": "Nist5", "hashrate": 17533, "power": 54, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a nist5" },
27 | { "name": "neoscrypt", "display": "NeoScrypt", "hashrate": 80, "power": 54, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a neoscrypt" },
28 | { "name": "scrypt", "display": "Scrypt", "hashrate": 540, "power": 60, "aparam1": "c:\\windows\\system32", "aparam2": "cmd.exe", "aparam3": "/c test-run.bat -a scrypt -batch" },
29 | { "name": "scryptn", "display": "Scrypt-N", "hashrate": 253, "power": 60, "aparam1": "c:\\windows\\system32", "aparam2": "cmd.exe", "aparam3": "/c test-run.bat -a scryptn -batch" },
30 | { "name": "keccak", "display": "Keccak", "hashrate": 301500, "power": 50, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a keccak" },
31 | { "name": "qubit", "display": "Qubit", "hashrate": 7500, "power": 50, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a qubit" },
32 | { "name": "lyra2", "display": "Lyra2RE", "hashrate": 1401, "power": 50, "aparam1": "", "aparam2": "TestMiner.exe", "aparam3": "-a lyra2re" },
33 | { "name": "sha256", "display": "SHA256", "hashrate": 10000, "power": 50, "aparam1": "c:\\windows\\system32", "aparam2": "cmd.exe", "aparam3": "/c test-run.bat -a sha256 -batch" }
34 | ],
35 | "nicehash": {
36 | "account": "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y",
37 | "worker": "1",
38 | "sparam1": "-o stratum+tcp://stratum.nicehash.com",
39 | "sparam2": "-p x",
40 | "weight": 0.90,
41 | "algos": [
42 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3336 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
43 | { "algo": "x13", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3337 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
44 | { "algo": "x15", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3339 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
45 | { "algo": "scrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3333 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
46 | { "algo": "scryptn", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3335 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
47 | { "algo": "keccak", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3338 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
48 | { "algo": "nist5", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3340 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
49 | { "algo": "neoscrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3341 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
50 | { "algo": "lyra2", "priceid": "9", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3342 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
51 | { "algo": "sha256", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3332 -u _ACCOUNT_._WORKER_ _SPARAM2_", "usewindow": true }
52 | ]
53 | },
54 | "westhash": {
55 | "account": "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y",
56 | "worker": "1",
57 | "sparam1": "-o stratum+tcp://stratum.westhash.com",
58 | "sparam2": "-p x",
59 | "algos": [
60 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3336 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
61 | { "algo": "x13", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3337 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
62 | { "algo": "x15", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3339 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
63 | { "algo": "scrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3333 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
64 | { "algo": "scryptn", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3335 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
65 | { "algo": "keccak", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3338 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
66 | { "algo": "nist5", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3340 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
67 | { "algo": "lyra2", "priceid": "9", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3342 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
68 | { "algo": "neoscrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3341 -u _ACCOUNT_._WORKER_ _SPARAM2_" }
69 | ]
70 | },
71 | "yaamp": {
72 | "account": "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y",
73 | "pricemode": 1,
74 | "sparam1": "-o stratum+tcp://yaamp.com",
75 | "sparam2": "-p x",
76 | "algos": [
77 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3533 -u _ACCOUNT_ _SPARAM2_" },
78 | { "algo": "x13", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3633 -u _ACCOUNT_ _SPARAM2_" },
79 | { "algo": "x14", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3933 -u _ACCOUNT_ _SPARAM2_" },
80 | { "algo": "x15", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3733 -u _ACCOUNT_ _SPARAM2_" },
81 | { "algo": "quark", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:4033 -u _ACCOUNT_ _SPARAM2_" },
82 | { "algo": "nist5", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3833 -u _ACCOUNT_ _SPARAM2_" },
83 | { "algo": "lyra2", "priceid": "lyra2", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:4433 -u _ACCOUNT_ _SPARAM2_" },
84 | { "algo": "scrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3433 -u _ACCOUNT_ _SPARAM2_" }
85 | ]
86 | },
87 | "wafflepool": {
88 | "account": "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y",
89 | "worker": "1",
90 | "sparam1": "-o stratum+tcp://useast.wafflepool.com",
91 | "sparam2": "-p x",
92 | "algos": [
93 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3331 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
94 | { "algo": "x13", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3330 _ACCOUNT_._WORKER_ _SPARAM2_" },
95 | { "algo": "scrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3333 _ACCOUNT_._WORKER_ _SPARAM2_" },
96 | { "algo": "scryptn", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3332 _ACCOUNT_._WORKER_ _SPARAM2_" }
97 | ]
98 | },
99 | "ltcrabbit": {
100 | "apikey": "mykey",
101 | "account": "MinerControl",
102 | "worker": "1",
103 | "sparam2": "-p x",
104 | "algos": [
105 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ -o stratum+tcp://x11.ltcrabbit.com:3332 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
106 | { "algo": "scrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ -o stratum+tcp://scrypt.ltcrabbit.com:3333 _ACCOUNT_._WORKER_ _SPARAM2_" }
107 | ]
108 | },
109 | "wepaybtc": {
110 | "account": "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y",
111 | "worker": "1",
112 | "sparam1": "-o ny",
113 | "sparam2": "-p MinerControl@StuffOfInterest.com",
114 | "algos": [
115 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_ -u _ACCOUNT___WORKER_ _SPARAM2_" },
116 | { "algo": "x13", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_ -u _ACCOUNT___WORKER_ _SPARAM2_" },
117 | { "algo": "x15", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_ -u _ACCOUNT___WORKER_ _SPARAM2_" },
118 | { "algo": "nist5", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_ -u _ACCOUNT___WORKER_ _SPARAM2_" }
119 | ]
120 | },
121 | "hamsterpool": {
122 | "apikey": "mykey",
123 | "donation": 1.0,
124 | "account": "MinerControl",
125 | "worker": "1",
126 | "sparam1": "-o stratum+tcp://eu.hamsterpool.com",
127 | "sparam2": "-p x",
128 | "algos": [
129 | { "algo": "scrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:7771 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
130 | { "algo": "scryptn", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:7772 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
131 | { "algo": "sha256", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:7774 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
132 | { "algo": "x11", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3508 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
133 | { "algo": "qubit", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:7776 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
134 | { "algo": "x13", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:7773 -u _ACCOUNT_._WORKER_ _SPARAM2_" },
135 | { "algo": "neoscrypt", "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ _SPARAM1_:3650 -u _ACCOUNT_._WORKER_ _SPARAM2_" }
136 | ]
137 | },
138 | "manual": {
139 | "account": "myaccount",
140 | "algos": [
141 | { "algo": "scrypt", "price": 0.0100, "fee": 3.0, "folder": "_APARAM1_", "command": "_APARAM2_", "arguments": "_APARAM3_ -o manual.com:1 _ACCOUNT_ -p x" }
142 | ]
143 | }
144 | }
--------------------------------------------------------------------------------
/MinerControl/MinerControl.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {94CC3F87-4215-4F3F-9524-695BF16FEBD0}
8 | WinExe
9 | Properties
10 | MinerControl
11 | MinerControl
12 | v4.0
13 | 512
14 |
15 |
16 |
17 | x86
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | bitcoin.ico
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | Form
66 |
67 |
68 | MainWindow.cs
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | MainWindow.cs
100 |
101 |
102 | Always
103 |
104 |
105 | Always
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | {63721d21-b76a-40ae-9a37-0c6f392cee63}
117 | TestMiner
118 |
119 |
120 |
121 |
128 |
--------------------------------------------------------------------------------
/MinerControl/MiningEngine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Threading;
8 | using System.Web.Script.Serialization;
9 | using System.Windows.Forms;
10 | using MinerControl.PriceEntries;
11 | using MinerControl.Services;
12 | using MinerControl.Utility;
13 | using MinerControl.Utility.Multicast;
14 |
15 | namespace MinerControl
16 | {
17 | public class MiningEngine
18 | {
19 | private const int RemotePortNumber = 12814;
20 |
21 | private Process _process;
22 | private IList _algorithmEntries = new List();
23 | private IList _priceEntries = new List();
24 | private IList _services = new List();
25 | private decimal _powerCost;
26 | private decimal _exchange;
27 | private string _currencyCode;
28 | private string _currencySymbol;
29 | private bool _logactivity;
30 | private PriceEntryBase _currentRunning;
31 | private DateTime? _startMining;
32 | private TimeSpan _minTime;
33 | private TimeSpan _maxTime;
34 | private TimeSpan _switchTime;
35 | private TimeSpan _deadtime;
36 | private int? _nextRun; // Next algo to run
37 | private DateTime? _nextRunFromTime; // When the next run algo became best
38 |
39 | public MiningModeEnum MiningMode { get; set; }
40 |
41 | public int MinerKillMode { get; private set; }
42 | public int GridSortMode { get; private set; }
43 | public int TrayMode { get; private set; } // How to handle minimizing ot the tray
44 |
45 | public int? CurrentRunning { get { return _currentRunning == null ? (int?)null : _currentRunning.Id; } }
46 | public int? NextRun { get { return _nextRun; } }
47 | public DateTime? StartMining { get { return _startMining; } }
48 | public decimal PowerCost { get { return _powerCost; } }
49 | public decimal Exchange { get { return _exchange; } }
50 | public string CurrencyCode { get { return _currencyCode; } }
51 | public string CurrencySymbol { get { return _currencySymbol; } }
52 | public TimeSpan DeadTime { get { return _deadtime; } }
53 |
54 | public TimeSpan? RestartTime
55 | {
56 | get
57 | {
58 | return _startMining.HasValue && _maxTime > TimeSpan.Zero
59 | ? _maxTime - (DateTime.Now - _startMining.Value)
60 | : (TimeSpan?)null;
61 | }
62 | }
63 |
64 | public TimeSpan? MiningTime
65 | {
66 | get
67 | {
68 | return _startMining.HasValue
69 | ? DateTime.Now - _startMining.Value
70 | : (TimeSpan?)null;
71 | }
72 | }
73 |
74 | // How long until next run starts
75 | public TimeSpan? NextRunTime
76 | {
77 | get
78 | {
79 | if (_nextRun == null || _nextRunFromTime == null || _startMining == null)
80 | return (TimeSpan?)null;
81 |
82 | var timeToSwitch = _switchTime - (DateTime.Now - _nextRunFromTime);
83 | var timeToMin = _minTime - (DateTime.Now - _startMining);
84 |
85 | return timeToMin > timeToSwitch ? timeToMin : timeToSwitch;
86 | }
87 | }
88 |
89 | public IList Services { get { return _services; } }
90 | public IList PriceEntries { get { return _priceEntries; } }
91 | public IList AlgorithmEntries { get { return _algorithmEntries; } }
92 |
93 | public TimeSpan TotalTime
94 | {
95 | get
96 | {
97 | var totalTime = PriceEntries.Sum(o => o.TimeMining.TotalMilliseconds);
98 | if (_startMining.HasValue)
99 | totalTime += (DateTime.Now - _startMining.Value).TotalMilliseconds;
100 | return TimeSpan.FromMilliseconds(totalTime);
101 | }
102 | }
103 |
104 | // Signals for UI updates
105 | private volatile bool _pricesUpdated;
106 | private volatile bool _hasPrices;
107 | public bool PricesUpdated { get { return _pricesUpdated; } set { _pricesUpdated = value; } }
108 | public bool HasPrices { get { return _hasPrices; } set { _hasPrices = value; } }
109 |
110 | #region Donation mining settings
111 |
112 | private double _donationpercentage = 0.02;
113 | public bool DoDonationMinging { get { return _donationpercentage > 0 && _donationfrequency > TimeSpan.Zero; } }
114 | private TimeSpan _donationfrequency = TimeSpan.FromMinutes(240);
115 | private TimeSpan _autoMiningTime = TimeSpan.Zero;
116 | private TimeSpan _donationMiningTime = TimeSpan.Zero;
117 | private MiningModeEnum _donationMiningMode = MiningModeEnum.Stopped;
118 |
119 | private TimeSpan MiningBeforeDonation
120 | {
121 | get
122 | {
123 | if (!DoDonationMinging) return TimeSpan.Zero;
124 | return TimeSpan.FromMinutes(_donationfrequency.TotalMinutes * (1 - _donationpercentage));
125 | }
126 | }
127 |
128 | private TimeSpan MiningDuringDonation
129 | {
130 | get
131 | {
132 | if (!DoDonationMinging) return TimeSpan.Zero;
133 | return _donationfrequency - MiningBeforeDonation;
134 | }
135 | }
136 |
137 | public TimeSpan TimeUntilDonation
138 | {
139 | get
140 | {
141 | if (!DoDonationMinging) return TimeSpan.Zero;
142 | var miningTime = _autoMiningTime;
143 | if (MiningMode == MiningModeEnum.Automatic && _startMining.HasValue) miningTime += (DateTime.Now - _startMining.Value);
144 | var value = MiningBeforeDonation - miningTime;
145 | return value < TimeSpan.Zero ? TimeSpan.Zero : value;
146 | }
147 | }
148 |
149 | public TimeSpan TimeDuringDonation
150 | {
151 | get
152 | {
153 | if (!DoDonationMinging) return TimeSpan.Zero;
154 | var miningTime = _donationMiningTime;
155 | if (MiningMode == MiningModeEnum.Donation && _startMining.HasValue) miningTime += (DateTime.Now - _startMining.Value);
156 | var value = MiningDuringDonation - miningTime;
157 | return value < TimeSpan.Zero ? TimeSpan.Zero : value;
158 | }
159 | }
160 |
161 | #endregion
162 |
163 | #region Remote console
164 |
165 | private bool _remoteSend;
166 | private bool _remoteReceive;
167 | private IPEndPoint _endPoint = new IPEndPoint(new IPAddress(new byte[] { 239, 14, 10, 30 }), RemotePortNumber);
168 | private MulticastSender _remoteSender;
169 | private MulticastReceiver _remoteReceiver;
170 |
171 | public bool RemoteReceive { get { return _remoteReceive; } }
172 |
173 | #endregion
174 |
175 | public MiningEngine()
176 | {
177 | MinerKillMode = 1;
178 | GridSortMode = 1;
179 | MiningMode = MiningModeEnum.Stopped;
180 | }
181 |
182 | public void Cleanup()
183 | {
184 | WriteConsoleAction = null;
185 |
186 | if (_currentRunning != null && _currentRunning.UseWindow == false)
187 | StopMiner();
188 |
189 | if (_process != null)
190 | _process.Dispose();
191 |
192 | if (_remoteSender != null)
193 | _remoteSender.Dispose();
194 |
195 | if (_remoteReceiver != null)
196 | _remoteReceiver.Dispose();
197 | }
198 |
199 | public bool LoadConfig()
200 | {
201 | const string configFile = "MinerControl.conf";
202 | if (!File.Exists(configFile))
203 | {
204 | MessageBox.Show(string.Format("Config file, '{0}', not found.", configFile), "Miner Control: Config file missing", MessageBoxButtons.OK, MessageBoxIcon.Error);
205 | return false;
206 | }
207 |
208 | Dictionary data;
209 |
210 | try
211 | {
212 | var pageString = File.ReadAllText(configFile);
213 | var serializer = new JavaScriptSerializer();
214 | data = serializer.DeserializeObject(pageString) as Dictionary;
215 | }
216 | catch (ArgumentException ex)
217 | {
218 | MessageBox.Show(string.Format("Error loading config file: '{0}'.", ex.Message), "Miner Control: Config file error", MessageBoxButtons.OK, MessageBoxIcon.Error);
219 | return false;
220 | }
221 |
222 | try
223 | {
224 | LoadConfigGeneral(data["general"] as Dictionary);
225 | LoadConfigAlgorithms(data["algorithms"] as object[]);
226 | }
227 | catch (Exception ex)
228 | {
229 | MessageBox.Show(string.Format("Error processing general configuration: '{0}'.", ex.Message), "Miner Control: Config file error", MessageBoxButtons.OK, MessageBoxIcon.Error);
230 | return false;
231 | }
232 |
233 | try
234 | {
235 | LoadService(new NiceHashService(), data, "nicehash");
236 | LoadService(new WestHashService(), data, "westhash");
237 | LoadService(new TradeMyBitService(), data, "trademybit");
238 | LoadService(new YaampService(), data, "yaamp");
239 | LoadService(new WafflePoolService(), data, "wafflepool");
240 | LoadService(new LtcRabbitService(), data, "ltcrabbit");
241 | LoadService(new WePayBtcService(), data, "wepaybtc");
242 | LoadService(new HamsterPoolService(), data, "hamsterpool");
243 | LoadService(new ManualService(), data, "manual");
244 |
245 | // Set Id for each entry
246 | for (var x = 0; x < _priceEntries.Count; x++)
247 | _priceEntries[x].Id = x + 1;
248 | }
249 | catch (Exception ex)
250 | {
251 | MessageBox.Show(string.Format("Error processing service configuration: '{0}'.", ex.Message), "Miner Control: Configuration file error", MessageBoxButtons.OK, MessageBoxIcon.Error);
252 | return false;
253 | }
254 |
255 | if (_remoteSend)
256 | {
257 | _remoteSender = new MulticastSender(_endPoint, 1);
258 | _remoteSender.Start();
259 | }
260 |
261 | if (_remoteReceive)
262 | {
263 | _remoteReceiver = new MulticastReceiver(_endPoint);
264 | _remoteReceiver.DataReceived += ProcessRemoteData;
265 | _remoteReceiver.Start();
266 | }
267 |
268 | return true;
269 | }
270 |
271 | private void LoadService(IService service, IDictionary data, string name)
272 | {
273 | if (!data.ContainsKey(name)) return;
274 | service.MiningEngine = this;
275 | _services.Add(service);
276 | service.Initialize(data[name] as Dictionary);
277 | }
278 |
279 | private void LoadConfigGeneral(IDictionary data)
280 | {
281 | _powerCost = data["power"].ExtractDecimal();
282 | _exchange = data["exchange"].ExtractDecimal();
283 | if (data.ContainsKey("currencycode"))
284 | _currencyCode = data["currencycode"].ToString().ToUpper();
285 | _minTime = TimeSpan.FromMinutes((double)data["mintime"].ExtractDecimal());
286 | _maxTime = TimeSpan.FromMinutes((double)data["maxtime"].ExtractDecimal());
287 | _switchTime = TimeSpan.FromMinutes((double)data["switchtime"].ExtractDecimal());
288 | _deadtime = TimeSpan.FromMinutes((double)data["deadtime"].ExtractDecimal());
289 |
290 | if (data.ContainsKey("logerrors"))
291 | ErrorLogger.LogExceptions = bool.Parse(data["logerrors"].ToString());
292 | if (data.ContainsKey("logactivity"))
293 | _logactivity = bool.Parse(data["logactivity"].ToString());
294 | if (data.ContainsKey("minerkillmode"))
295 | MinerKillMode = int.Parse(data["minerkillmode"].ToString());
296 | if (data.ContainsKey("gridsortmode"))
297 | GridSortMode = int.Parse(data["gridsortmode"].ToString());
298 | if (data.ContainsKey("traymode"))
299 | TrayMode = int.Parse(data["traymode"].ToString());
300 | if (Program.MinimizeToTray && TrayMode == 0)
301 | TrayMode = 2;
302 | if (data.ContainsKey("donationpercentage"))
303 | _donationpercentage = (double)(data["donationpercentage"].ExtractDecimal()) / 100;
304 | if (data.ContainsKey("donationfrequency"))
305 | _donationfrequency = TimeSpan.FromMinutes((double)data["donationfrequency"].ExtractDecimal());
306 | if (data.ContainsKey("remotesend"))
307 | _remoteSend = bool.Parse(data["remotesend"].ToString());
308 | if (data.ContainsKey("remotereceive"))
309 | _remoteReceive = bool.Parse(data["remotereceive"].ToString());
310 | }
311 |
312 | private void LoadConfigAlgorithms(object[] data)
313 | {
314 | foreach (var rawitem in data)
315 | {
316 | var item = rawitem as Dictionary;
317 | var entry = new AlgorithmEntry
318 | {
319 | Name = item["name"] as string,
320 | Display = item.ContainsKey("display") ? item["display"] as string : GetAlgoDisplayName(item["name"] as string),
321 | Hashrate = item["hashrate"].ExtractDecimal(),
322 | Power = item["power"].ExtractDecimal(),
323 | Param1 = item.GetString("aparam1") ?? string.Empty,
324 | Param2 = item.GetString("aparam2") as string ?? string.Empty,
325 | Param3 = item.GetString("aparam3") as string ?? string.Empty
326 | };
327 |
328 | _algorithmEntries.Add(entry);
329 | }
330 | }
331 |
332 | public void StopMiner()
333 | {
334 | if (!_process.IsRunning())
335 | {
336 | _process = null;
337 | return;
338 | }
339 |
340 | LogActivity(_donationMiningMode == MiningModeEnum.Donation ? "DonationStop" : "Stop");
341 | WriteConsole(string.Format("Stopping {0} {1}", _currentRunning.ServicePrint, _currentRunning.AlgoName), true);
342 | RecordMiningTime();
343 | if (MinerKillMode == 0)
344 | ProcessUtil.KillProcess(_process);
345 | else
346 | ProcessUtil.KillProcessAndChildren(_process.Id);
347 |
348 | _process = null;
349 | _donationMiningMode = MiningModeEnum.Stopped;
350 |
351 | if (_currentRunning != null)
352 | {
353 | var entry = PriceEntries.Where(o => o.Id == _currentRunning.Id).Single();
354 | entry.UpdateStatus();
355 | }
356 |
357 | _currentRunning = null;
358 | }
359 |
360 | private void RecordMiningTime()
361 | {
362 | if (_currentRunning == null || !_startMining.HasValue) return;
363 |
364 | if (_donationMiningMode == MiningModeEnum.Automatic) _autoMiningTime += (DateTime.Now - _startMining.Value);
365 | if (_donationMiningMode == MiningModeEnum.Donation) _donationMiningTime += (DateTime.Now - _startMining.Value);
366 |
367 | _currentRunning.TimeMining += (DateTime.Now - _startMining.Value);
368 | _currentRunning.UpdateStatus();
369 | _startMining = null;
370 | }
371 |
372 | private void StartMiner(PriceEntryBase entry, bool isMinimizedToTray = false)
373 | {
374 | _nextRun = null;
375 | _nextRunFromTime = null;
376 | _currentRunning = entry;
377 | _startMining = DateTime.Now;
378 |
379 | _process = new Process();
380 | if (_donationMiningMode == MiningModeEnum.Donation)
381 | {
382 | if (!string.IsNullOrWhiteSpace(entry.DonationFolder))
383 | _process.StartInfo.WorkingDirectory = entry.DonationFolder;
384 | _process.StartInfo.FileName = string.IsNullOrWhiteSpace(entry.DonationFolder)
385 | ? entry.DonationCommand
386 | : string.Format(@"{0}\{1}", entry.DonationFolder, entry.DonationCommand);
387 | _process.StartInfo.Arguments = entry.DonationArguments;
388 | }
389 | else
390 | {
391 | if (!string.IsNullOrWhiteSpace(entry.Folder))
392 | _process.StartInfo.WorkingDirectory = entry.Folder;
393 | _process.StartInfo.FileName = string.IsNullOrWhiteSpace(entry.Folder)
394 | ? entry.Command
395 | : string.Format(@"{0}\{1}", entry.Folder, entry.Command);
396 | _process.StartInfo.Arguments = entry.Arguments;
397 | }
398 |
399 | WriteConsole(string.Format("Starting {0} {1} with {2} {3}", _currentRunning.ServicePrint, _currentRunning.Name, _process.StartInfo.FileName, _process.StartInfo.Arguments), true);
400 |
401 | if (!string.IsNullOrWhiteSpace(_process.StartInfo.WorkingDirectory) && !Directory.Exists(_process.StartInfo.WorkingDirectory))
402 | {
403 | entry.DeadTime = DateTime.Now;
404 | var message = string.Format("Path '{0}' does not exist.", _process.StartInfo.WorkingDirectory);
405 | _process = null;
406 | WriteConsole(message, true);
407 | throw new ArgumentException(message);
408 | }
409 | if (!string.IsNullOrWhiteSpace(_process.StartInfo.FileName) && !File.Exists(_process.StartInfo.FileName))
410 | {
411 | entry.DeadTime = DateTime.Now;
412 | var message = string.Format("File '{0}' does not exist.", _process.StartInfo.FileName);
413 | _process = null;
414 | WriteConsole(message, true);
415 | throw new ArgumentException(message);
416 | }
417 |
418 | if (entry.UseWindow)
419 | {
420 | _process.StartInfo.WindowStyle = (isMinimizedToTray && TrayMode == 2) ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Minimized;
421 | _process.Start();
422 |
423 | Thread.Sleep(100);
424 | try
425 | {
426 | ProcessUtil.SetWindowTitle(_process, string.Format("{0} {1} Miner", entry.ServicePrint, entry.Name));
427 | }
428 | catch (Exception ex)
429 | {
430 | ErrorLogger.Log(ex);
431 | }
432 |
433 | if (isMinimizedToTray && TrayMode == 1)
434 | HideMinerWindow();
435 | }
436 | else
437 | {
438 | _process.StartInfo.RedirectStandardOutput = true;
439 | _process.StartInfo.RedirectStandardError = true;
440 | _process.EnableRaisingEvents = true;
441 | _process.StartInfo.CreateNoWindow = true;
442 | _process.StartInfo.UseShellExecute = false;
443 |
444 | _process.ErrorDataReceived += ProcessConsoleOutput;
445 | _process.OutputDataReceived += ProcessConsoleOutput;
446 |
447 | _process.Start();
448 |
449 | _process.BeginOutputReadLine();
450 | _process.BeginErrorReadLine();
451 | }
452 |
453 | _startMining = DateTime.Now;
454 | _donationMiningMode = MiningMode;
455 |
456 | entry.UpdateStatus();
457 |
458 | LogActivity(_donationMiningMode == MiningModeEnum.Donation ? "DonationStart" : "Start");
459 | }
460 |
461 | private void ClearDeadTimes()
462 | {
463 | foreach (var entry in _priceEntries)
464 | entry.DeadTime = DateTime.MinValue;
465 | }
466 |
467 | public void RequestStop()
468 | {
469 | _nextRun = null;
470 | _nextRunFromTime = null;
471 |
472 | StopMiner();
473 | ClearDeadTimes();
474 | }
475 |
476 | public void RequestStart(int id, bool isMinimizedToTray = false)
477 | {
478 | var entry = _priceEntries.Single(o => o.Id == id);
479 | StartMiner(entry, isMinimizedToTray);
480 | }
481 |
482 | public void CheckPrices()
483 | {
484 | foreach (var service in _services)
485 | service.CheckPrices();
486 | }
487 |
488 | public void RunBestAlgo(bool isMinimizedToTray)
489 | {
490 | try
491 | {
492 | // Check for dead process
493 | if (!_process.IsRunning() && _currentRunning != null)
494 | {
495 | lock (this)
496 | {
497 | _currentRunning.DeadTime = DateTime.Now;
498 | LogActivity(_donationMiningMode == MiningModeEnum.Donation ? "DonationDead" : "Dead");
499 | WriteConsole(string.Format("Dead {0} {1}", _currentRunning.ServicePrint, _currentRunning.Name), true);
500 | RecordMiningTime();
501 | }
502 | }
503 |
504 | // Clear information if process not running
505 | if (_process == null || _process.HasExited)
506 | {
507 | _currentRunning = null;
508 | _startMining = null;
509 | _nextRun = null;
510 | _nextRunFromTime = null;
511 | }
512 |
513 | // Donation mining
514 | if (DoDonationMinging)
515 | {
516 | if (_donationMiningMode == MiningModeEnum.Automatic && TimeUntilDonation == TimeSpan.Zero)
517 | {
518 | StopMiner();
519 | _donationMiningMode = MiningModeEnum.Donation;
520 | MiningMode = _donationMiningMode;
521 | _autoMiningTime = TimeSpan.Zero;
522 | }
523 | else if (_donationMiningMode == MiningModeEnum.Donation && TimeDuringDonation == TimeSpan.Zero)
524 | {
525 | StopMiner();
526 | _donationMiningMode = MiningModeEnum.Automatic;
527 | MiningMode = _donationMiningMode;
528 | _donationMiningTime = TimeSpan.Zero;
529 | }
530 | }
531 |
532 | // Restart miner if max time reached
533 | if (RestartTime.HasValue && RestartTime.Value <= TimeSpan.Zero)
534 | StopMiner();
535 |
536 | // Find the best, live entry
537 | var best = _donationMiningMode == MiningModeEnum.Donation
538 | ? _priceEntries
539 | .Where(o => !o.IsDead)
540 | .Where(o => !string.IsNullOrWhiteSpace(o.DonationCommand))
541 | .OrderByDescending(o => o.NetEarn)
542 | .First()
543 | : _priceEntries
544 | .Where(o => !o.IsDead)
545 | .Where(o => !string.IsNullOrWhiteSpace(o.Command))
546 | .OrderByDescending(o => o.NetEarn)
547 | .First();
548 |
549 | // Handle minimum time for better algorithm before switching
550 | if (_switchTime > TimeSpan.Zero && _currentRunning != null)
551 | {
552 | if (!_nextRun.HasValue && _currentRunning.Id != best.Id)
553 | {
554 | _nextRun = best.Id;
555 | _nextRunFromTime = DateTime.Now;
556 | }
557 | else if (_nextRun.HasValue && _currentRunning.Id == best.Id)
558 | {
559 | _nextRun = null;
560 | _nextRunFromTime = null;
561 | }
562 | if (NextRunTime.HasValue && NextRunTime > TimeSpan.Zero)
563 | best = _priceEntries.First(o => o.Id == _currentRunning.Id);
564 | }
565 |
566 | // Update undead entries
567 | var entries = PriceEntries.Where(o => !o.IsDead && o.DeadTime != DateTime.MinValue);
568 | foreach (var entry in entries)
569 | entry.DeadTime = DateTime.MinValue;
570 |
571 | // Just update time if we are already running the right entry
572 | if (_currentRunning != null && _currentRunning.Id == best.Id)
573 | {
574 | _currentRunning.UpdateStatus();
575 | return;
576 | }
577 |
578 | // Honor minimum time to run in auto mode
579 | if (MiningTime.HasValue && MiningTime.Value < _minTime)
580 | {
581 | _currentRunning.UpdateStatus();
582 | return;
583 | }
584 |
585 | StopMiner();
586 | StartMiner(best, isMinimizedToTray);
587 | }
588 | catch (Exception ex)
589 | {
590 | ErrorLogger.Log(ex);
591 | }
592 | }
593 |
594 | public void HideMinerWindow()
595 | {
596 | if (_currentRunning == null || !_currentRunning.UseWindow) return;
597 |
598 | ProcessUtil.HideWindow(_process);
599 | }
600 |
601 | public void MinimizeMinerWindow()
602 | {
603 | if (_currentRunning == null || !_currentRunning.UseWindow) return;
604 |
605 | ProcessUtil.MinimizeWindow(_process);
606 | }
607 |
608 | public void LoadExchangeRates()
609 | {
610 | WebUtil.DownloadJson("http://blockchain.info/ticker", ProcessExchangeRates);
611 | }
612 |
613 | private void ProcessExchangeRates(object jsonData)
614 | {
615 | var data = jsonData as Dictionary;
616 | if (!data.ContainsKey(_currencyCode)) return;
617 | var item = data[_currencyCode] as Dictionary;
618 | var exchange = item["last"].ExtractDecimal();
619 | var symbol = item["symbol"].ToString();
620 | lock (this)
621 | {
622 | if (exchange > 0 && exchange != _exchange)
623 | {
624 | _exchange = exchange;
625 | if (PriceEntries != null)
626 | foreach (var entry in PriceEntries)
627 | entry.UpdateExchange();
628 | if (Services != null)
629 | foreach (var service in Services)
630 | service.UpdateExchange();
631 | }
632 |
633 | if (!string.IsNullOrWhiteSpace(symbol)) _currencySymbol = symbol;
634 | }
635 | }
636 |
637 | private void LogActivity(string action)
638 | {
639 | if (!_logactivity) return;
640 |
641 | var items = new[]
642 | {
643 | DateTime.Now.ToString("s"),
644 | action,
645 | MiningMode.ToString(),
646 | _currentRunning != null ? _currentRunning.ServicePrint : string.Empty,
647 | _currentRunning != null ? _currentRunning.AlgoName : string.Empty,
648 | _currentRunning != null ? _currentRunning.Price.ToString("F6") : string.Empty,
649 | _currentRunning != null ? _currentRunning.Earn.ToString("F6") : string.Empty,
650 | _currentRunning != null ? _currentRunning.Fees.ToString("F6") : string.Empty,
651 | _currentRunning != null ? _currentRunning.Power.ToString("F6") : string.Empty,
652 | _currentRunning != null ? _currentRunning.NetEarn.ToString("F6") : string.Empty,
653 | _exchange.ToString("F2"),
654 | _currentRunning != null ? _currentRunning.ServiceEntry.Balance.ToString("F8") : string.Empty
655 | };
656 |
657 | var line = string.Join(",", items);
658 | const string logfile = "activity.log";
659 |
660 | var exists = File.Exists(logfile);
661 | using (var w = exists ? File.AppendText(logfile) : File.CreateText(logfile))
662 | {
663 | if (!exists)
664 | w.WriteLine("time,action,mode,service,algo,price,earn,fees,power,netearn,exchange,servicebalance");
665 | w.WriteLine(line);
666 | }
667 | }
668 |
669 | #region Console interaction
670 |
671 | public Action WriteConsoleAction { get; set; }
672 |
673 | private void WriteConsole(string text, bool prefixTime = false)
674 | {
675 | if (WriteConsoleAction == null) return;
676 |
677 | if (prefixTime)
678 | text = string.Format("[{0:HH:mm:ss}] {1}", DateTime.Now, text);
679 |
680 | WriteConsoleAction(text);
681 |
682 | if (_remoteSender == null) return;
683 | text = string.Format("{0} {1}", "CON", text);
684 | _remoteSender.Send(text);
685 | }
686 |
687 | private void ProcessConsoleOutput(object sender, DataReceivedEventArgs e)
688 | {
689 | if (e.Data == null) return;
690 | WriteConsole(e.Data);
691 | }
692 |
693 | public Action WriteRemoteAction { get; set; }
694 |
695 | private void ProcessRemoteData(object sender, MulticastDataReceivedEventArgs e)
696 | {
697 | if (WriteRemoteAction == null) return;
698 |
699 | try
700 | {
701 | var data = e.StringData;
702 | var command = data.Substring(0, 4);
703 | var body = data.Substring(4);
704 |
705 | switch (command)
706 | {
707 | case "CON ":
708 | WriteRemoteAction(e.RemoteEndPoint.Address, body);
709 | break;
710 | }
711 | }
712 | catch (Exception ex)
713 | {
714 | ErrorLogger.Log(ex);
715 | }
716 | }
717 |
718 | #endregion
719 |
720 | #region Helpers
721 |
722 | private readonly IDictionary _algoNames = new Dictionary
723 | {
724 | {"x11", "X11"},
725 | {"x13", "X13"},
726 | {"x14", "X14"},
727 | {"x15", "X15"},
728 | {"scrypt", "Scrypt"},
729 | {"scryptn", "Scrypt-N"},
730 | {"sha256", "SHA256"},
731 | {"nist5", "Nist5"},
732 | {"keccak", "Keccak"},
733 | {"quark", "Quark"},
734 | {"neoscrypt", "NeoScrypt"}
735 | };
736 |
737 | private string GetAlgoDisplayName(string rawname)
738 | {
739 | if (_algoNames.ContainsKey(rawname))
740 | return _algoNames[rawname];
741 | return rawname;
742 | }
743 |
744 | #endregion
745 | }
746 | }
747 |
--------------------------------------------------------------------------------
/MinerControl/MiningModeEnum.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl
7 | {
8 | public enum MiningModeEnum
9 | {
10 | Stopped,
11 | Manual,
12 | Automatic,
13 | Donation
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/HamsterPoolPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class HamsterPoolPriceEntry : PriceEntryBase
9 | {
10 | public override decimal Fees
11 | {
12 | get { return Earn * (0.015m + Donation); }
13 | set { base.Fees = value; }
14 | }
15 |
16 | public decimal Donation { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/LtcRabbitPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class LtcRabbitPriceEntry : PriceEntryBase
9 | {
10 | public override decimal Fees
11 | {
12 | get { return Earn * 0.02m; }
13 | set { base.Fees = value; }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/ManualPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class ManualPriceEntry : PriceEntryBase
9 | {
10 | public decimal FeePercent { get; set; }
11 |
12 | public override decimal Fees
13 | {
14 | get { return Earn * (FeePercent / 100); }
15 | set { base.Fees = value; }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/NiceHashPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class NiceHashPriceEntry : PriceEntryBase
9 | {
10 | public override decimal Fees
11 | {
12 | get { return Earn * 0.02m; }
13 | set { base.Fees = value; }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/PriceEntryBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using MinerControl.Services;
4 | using MinerControl.Utility;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public abstract class PriceEntryBase : PropertyChangedBase
9 | {
10 | public PriceEntryBase()
11 | {
12 | Weight = 1.0m;
13 | DeadTime = DateTime.MinValue;
14 | }
15 |
16 | public MiningEngine MiningEngine { get; set; }
17 | public int Id { get; set; }
18 | public IService ServiceEntry { get; set; }
19 | public string PriceId { get; set; }
20 | public string AlgoName { get; set; }
21 | public string Name { get; set; }
22 | public bool UseWindow { get; set; }
23 |
24 | public decimal Hashrate { get; set; }
25 | public decimal Power { get; set; }
26 | public string Folder { get; set; }
27 | public string Command { get; set; }
28 | public string Arguments { get; set; }
29 | public string DonationFolder { get; set; }
30 | public string DonationCommand { get; set; }
31 | public string DonationArguments { get; set; }
32 |
33 | private decimal _price;
34 | private decimal _fees;
35 | private decimal _weight;
36 | private decimal _balance;
37 | private decimal _acceptSpeed;
38 | private decimal _rejectSpeed;
39 | private TimeSpan _timeMining;
40 | private DateTime _deadTime;
41 |
42 | public decimal Price { get { return _price; } set { SetField(ref _price, value, () => Price, () => Earn, () => Fees, () => NetEarn); } }
43 | public decimal Earn { get { return Price / 1000 * Hashrate / 1000; } }
44 | public decimal PowerCost { get { return Power / 1000 * 24 * MiningEngine.PowerCost / MiningEngine.Exchange; } }
45 | public virtual decimal Fees { get { return _fees; } set { SetField(ref _fees, value, () => Fees, () => NetEarn); } }
46 | public decimal Weight { get { return _weight; } set { SetField(ref _weight, value, () => Weight, () => NetEarn); } }
47 | public decimal NetEarn { get { return ((Earn - Fees) * Weight) - PowerCost; } }
48 |
49 | public decimal Balance { get { return _balance; } set { SetField(ref _balance, value, () => Balance, () => BalancePrint); } }
50 | public decimal AcceptSpeed { get { return _acceptSpeed; } set { SetField(ref _acceptSpeed, value, () => AcceptSpeed, () => AcceptSpeedPrint); } }
51 | public decimal RejectSpeed { get { return _rejectSpeed; } set { SetField(ref _rejectSpeed, value, () => RejectSpeed, () => RejectSpeedPrint); } }
52 |
53 | public TimeSpan TimeMining { get { return _timeMining; } set { SetField(ref _timeMining, value, () => TimeMining, () => TimeMiningPrint); } }
54 | public DateTime DeadTime { get { return _deadTime; } set { SetField(ref _deadTime, value, () => DeadTime, () => StatusPrint); } }
55 |
56 | public bool IsDead { get { return (DeadTime + MiningEngine.DeadTime) > DateTime.Now; } }
57 | public TimeSpan TimeMiningWithCurrent
58 | {
59 | get
60 | {
61 | return MiningEngine.CurrentRunning.HasValue && MiningEngine.CurrentRunning.Value == Id && MiningEngine.StartMining.HasValue
62 | ? (TimeMining + (DateTime.Now - MiningEngine.StartMining.Value))
63 | : TimeMining;
64 | }
65 | }
66 |
67 | public string ServicePrint { get { return ServiceEntry.ServiceEnum.ToString(); } }
68 | public string BalancePrint { get { return Balance == 0.0m ? string.Empty : Balance.ToString("N8"); } }
69 | public string AcceptSpeedPrint { get { return AcceptSpeed == 0.0m ? string.Empty : AcceptSpeed.ToString("N2"); } }
70 | public string RejectSpeedPrint { get { return RejectSpeed == 0.0m ? string.Empty : RejectSpeed.ToString("N2"); } }
71 | public string TimeMiningPrint { get { return TimeMiningWithCurrent.FormatTime(true); } }
72 |
73 | public string StatusPrint
74 | {
75 | get
76 | {
77 | if (MiningEngine.CurrentRunning.HasValue && MiningEngine.CurrentRunning.Value == Id)
78 | return "Running";
79 | if (IsDead)
80 | return "Dead";
81 | if (MiningEngine.NextRun.HasValue && MiningEngine.NextRun.Value == Id)
82 | return "Pending";
83 | return string.Empty;
84 | }
85 | }
86 |
87 | public void UpdateStatus()
88 | {
89 | OnPropertyChanged(() => StatusPrint);
90 | OnPropertyChanged(() => TimeMiningPrint);
91 | ServiceEntry.UpdateTime();
92 | }
93 |
94 | public void UpdateExchange()
95 | {
96 | OnPropertyChanged(() => PowerCost);
97 | OnPropertyChanged(() => NetEarn);
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/TradeMyBitPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class TradeMyBitPriceEntry : PriceEntryBase
9 | {
10 | public override decimal Fees
11 | {
12 | get { return Earn * 0.025m; }
13 | set { base.Fees = value; }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/WafflePoolPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class WafflePoolPriceEntry : PriceEntryBase
9 | {
10 | public override decimal Fees
11 | {
12 | get { return Earn * 0.02m; }
13 | set { base.Fees = value; }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/WePayBtcPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class WePayBtcPriceEntry : PriceEntryBase
9 | {
10 | public override decimal Fees
11 | {
12 | //get { return Earn * 0.02m; }
13 | get { return 0m; }
14 | set { base.Fees = value; }
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/MinerControl/PriceEntries/YaampPriceEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl.PriceEntries
7 | {
8 | public class YaampPriceEntry : PriceEntryBase
9 | {
10 | public decimal FeePercent { get; set; }
11 |
12 | public override decimal Fees
13 | {
14 | get { return Earn * (FeePercent / 100); }
15 | set { base.Fees = value; }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MinerControl/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Permissions;
3 | using System.Threading;
4 | using System.Windows.Forms;
5 | using MinerControl.Utility;
6 |
7 | namespace MinerControl
8 | {
9 | static class Program
10 | {
11 | public static bool HasAutoStart { get; set; }
12 | public static bool MinimizeToTray { get; set; }
13 | public static bool MinimizeOnStart { get; set; }
14 |
15 | ///
16 | /// The main entry point for the application.
17 | ///
18 | [STAThread]
19 | [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
20 | static void Main(string[] args)
21 | {
22 | foreach (var arg in args)
23 | {
24 | switch (arg)
25 | {
26 | case "-a":
27 | case "--auto-start":
28 | HasAutoStart = true;
29 | break;
30 | case "-t":
31 | case "--minimize-to-tray":
32 | MinimizeToTray = true;
33 | break;
34 | case "-m":
35 | case "--minimize":
36 | MinimizeOnStart = true;
37 | break;
38 | }
39 | }
40 |
41 | Application.EnableVisualStyles();
42 | Application.SetCompatibleTextRenderingDefault(false);
43 |
44 | Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(LastResortThreadExceptionHandler);
45 | Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
46 | AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(LastResortDomainExceptionHandler);
47 |
48 | Application.Run(new MainWindow());
49 | }
50 |
51 | private static void LastResortThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
52 | {
53 | ErrorLogger.Log(e.Exception);
54 | }
55 |
56 | private static void LastResortDomainExceptionHandler(object sender, UnhandledExceptionEventArgs e)
57 | {
58 | var ex = (Exception)e.ExceptionObject;
59 | ErrorLogger.Log(ex);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/MinerControl/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MinerControl")]
9 | [assembly: AssemblyDescription("Algorithm switching control for mining services")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Miner Control")]
13 | [assembly: AssemblyCopyright("Copyright © 2014 StuffOfInterest aka Delbert Matlock")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("13172645-6ea5-463e-9d8b-a9ac8258f9bf")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.6.1.0")]
36 | [assembly: AssemblyFileVersion("1.6.1.0")]
37 |
--------------------------------------------------------------------------------
/MinerControl/ServiceEnum.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MinerControl
7 | {
8 | public enum ServiceEnum
9 | {
10 | NiceHash,
11 | WestHash,
12 | TradeMyBit,
13 | YAAMP,
14 | WafflePool,
15 | LTCRabbit,
16 | WePayBTC,
17 | HamsterPool,
18 | Manual
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MinerControl/Services/HamsterPoolService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using MinerControl.PriceEntries;
6 | using MinerControl.Utility;
7 |
8 | namespace MinerControl.Services
9 | {
10 | public class HamsterPoolService : ServiceBase
11 | {
12 | // https://hamsterpool.com/index.php?page=api&action=algorithm_btc_per_mh
13 | // {"scrypt":"0.00015374509140941","nscrypt":"0.0012163696966358","sha256":"1.2994452372168E-8","x11":"0.00012615553588975","qubit":"0.00034249512834947","x13":"0.00019299647643157","neoscrypt":"0.0080657456143128"}
14 |
15 | // https://hamsterpool.com/index.php?page=api&action=user_algorithm_balance_btc&api_key=[apikey]
16 | // {"scrypt":0,"nscrypt":0,"x11":8.074500888863218e-8,"x13":0,"sha256":0,"qubit":0,"neoscrypt":0}
17 |
18 | private string _apikey;
19 | private decimal _donation;
20 |
21 | public HamsterPoolService()
22 | {
23 | ServiceEnum = ServiceEnum.HamsterPool;
24 | //DonationAccount = "MinerControl"; //Too hard to configure donation for this one.
25 | //DonationWorker = "1";
26 |
27 | AlgoTranslations = new Dictionary
28 | {
29 | {"nscrypt", "scryptn"}
30 | };
31 | }
32 |
33 | public override void Initialize(IDictionary data)
34 | {
35 | ExtractCommon(data);
36 | _apikey = data.GetString("apikey");
37 | _donation = data["donation"].ExtractDecimal() / 100;
38 |
39 | var items = data["algos"] as object[];
40 | foreach (var rawitem in items)
41 | {
42 | var item = rawitem as Dictionary;
43 | var entry = CreateEntry(item);
44 | entry.Donation = _donation;
45 |
46 | Add(entry);
47 | }
48 | }
49 |
50 | public override void CheckPrices()
51 | {
52 | ClearStalePrices();
53 | WebUtil.DownloadJson(string.Format("https://hamsterpool.com/index.php?page=api&action=algorithm_btc_per_mh", _apikey), ProcessPrices);
54 | WebUtil.DownloadJson(string.Format("https://hamsterpool.com/index.php?page=api&action=user_algorithm_balance_btc&api_key={0}", _apikey), ProcessBalances);
55 | }
56 |
57 | private void ProcessPrices(object jsonData)
58 | {
59 | var data = jsonData as Dictionary;
60 | lock (MiningEngine)
61 | {
62 | foreach (var key in data.Keys)
63 | {
64 | var algo = key.ToLower();
65 | var price = data[key].ExtractDecimal();
66 |
67 | var entry = GetEntry(algo);
68 | if (entry == null) continue;
69 |
70 | entry.Price = price * 1000;
71 | }
72 |
73 | MiningEngine.PricesUpdated = true;
74 | MiningEngine.HasPrices = true;
75 |
76 | LastUpdated = DateTime.Now;
77 | }
78 | }
79 |
80 | private void ProcessBalances(object jsonData)
81 | {
82 | var data = jsonData as Dictionary;
83 | lock (MiningEngine)
84 | {
85 | foreach (var key in data.Keys)
86 | {
87 | var algo = key.ToLower();
88 | var balance = data[key].ExtractDecimal();
89 |
90 | var entry = GetEntry(algo);
91 | if (entry == null) continue;
92 |
93 | entry.Balance = balance;
94 | }
95 |
96 | Balance = PriceEntries.Sum(o => o.Balance);
97 |
98 | MiningEngine.PricesUpdated = true;
99 | MiningEngine.HasPrices = true;
100 |
101 | LastUpdated = DateTime.Now;
102 | }
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/MinerControl/Services/IService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 |
5 | namespace MinerControl.Services
6 | {
7 | public interface IService : INotifyPropertyChanged
8 | {
9 | MiningEngine MiningEngine { get; set; }
10 | ServiceEnum ServiceEnum { get; }
11 | DateTime? LastUpdated { get; }
12 | decimal Balance { get; }
13 | decimal Currency { get; }
14 |
15 | string ServicePrint { get; }
16 | string LastUpdatedPrint { get; }
17 | string BalancePrint { get; }
18 | string CurrencyPrint { get; }
19 | string TimeMiningPrint { get; }
20 |
21 | void Initialize(IDictionary data);
22 | void CheckPrices();
23 | void UpdateTime();
24 | void UpdateExchange();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MinerControl/Services/LtcRabbitService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using MinerControl.PriceEntries;
6 | using MinerControl.Utility;
7 |
8 | namespace MinerControl.Services
9 | {
10 | public class LtcRabbitService : ServiceBase
11 | {
12 | // https://www.ltcrabbit.com/index.php?page=api&action=public
13 | // {"hashrate":2394110,"hashrate_scrypt":2394110,"hashrate_x11":3971072,"workers":1765,"ltc_mh_scrypt":"0.0257857","ltc_mh_x11":"0.0328172",
14 | // "profitability":
15 | // {"current":{
16 | // "scrypt":{"ltc_mh":"0.0257857","btc_mh":"0.0002651","vs_ltc":"93.60"},
17 | // "x11":{"ltc_mh":"0.0328172","btc_mh":"0.0003374","vs_ltc":"476.49"}},
18 | // "history":{
19 | // "scrypt":[{"date":"2014-10-20","ltc_mh":"0.0171152","btc_mh":"0.0001757","vs_ltc":"62.08"},],
20 | // "x11":[{"date":"2014-10-20","ltc_mh":"0.0303198","btc_mh":"0.0003113","vs_ltc":"439.88"},]}
21 | // }}
22 |
23 | // https://www.ltcrabbit.com/index.php?page=api&action=getappdata&appname=general&appversion=1&api_key=
24 | // {"getappdata":{
25 | // "general":{"message":""},
26 | // "pool":{"hashrate_scrypt":2271520,"hashrate_x11":3859754,"workers":1783,"ltc_mh_scrypt":"0.0254868","ltc_mh_x11":"0.0323970","hashrate":2271520},
27 | // "profitability": ,
28 | // "ltc_exchange_rates":{"USD":"3.88","EUR":"3.104"},
29 | // "btc_exchange_rates":{"USD":"379.736","EUR":"301.00000"},
30 | // "user":{"username":"MinerControl","balance":0,"balance_btc":"0.0000033","hashrate_scrypt":0,"hashrate_x11":0,"invalid_shares_scrypt":0,"invalid_shares_x11":0,"sharerate":0,"invalid_share_rate":0,"hashrate":0},
31 | // "worker":[],
32 | // "earnings":{"basis":[],"alt":[],"24h_total":0,"24h_basis":0,"24h_alt":0,"24h_affiliate":0,"48h_total":0,"48h_basis":0,"48h_alt":0,"48h_affiliate":0}}}
33 |
34 | private string _apikey;
35 |
36 | public LtcRabbitService()
37 | {
38 | ServiceEnum = ServiceEnum.LTCRabbit;
39 | DonationAccount = "MinerControl";
40 | DonationWorker = "1";
41 | }
42 |
43 | public override void Initialize(IDictionary data)
44 | {
45 | ExtractCommon(data);
46 | _apikey = data.GetString("apikey");
47 |
48 | var items = data["algos"] as object[];
49 | foreach (var rawitem in items)
50 | {
51 | var item = rawitem as Dictionary;
52 | var entry = CreateEntry(item);
53 |
54 | Add(entry);
55 | }
56 | }
57 |
58 | public override void CheckPrices()
59 | {
60 | ClearStalePrices();
61 | WebUtil.DownloadJson("https://www.ltcrabbit.com/index.php?page=api&action=public", ProcessPrices);
62 | WebUtil.DownloadJson(string.Format("https://www.ltcrabbit.com/index.php?page=api&action=getappdata&appname=MinerControl&appversion=1&api_key={0}", _apikey), ProcessBalances);
63 | }
64 |
65 | private void ProcessPrices(object jsonData)
66 | {
67 | var data = jsonData as Dictionary;
68 | var profitability = data["profitability"] as Dictionary;
69 | var current = profitability["current"] as Dictionary;
70 |
71 | lock (MiningEngine)
72 | {
73 | foreach (var key in current.Keys)
74 | {
75 | var rawitem = current[key];
76 | var item = rawitem as Dictionary;
77 | var algo = key.ToLower();
78 |
79 | var entry = GetEntry(algo);
80 | if (entry == null) continue;
81 |
82 | entry.Price = item["btc_mh"].ExtractDecimal() * 1000;
83 | }
84 |
85 | MiningEngine.PricesUpdated = true;
86 | MiningEngine.HasPrices = true;
87 |
88 | LastUpdated = DateTime.Now;
89 | }
90 | }
91 |
92 | private void ProcessBalances(object jsonData)
93 | {
94 | var data = jsonData as Dictionary;
95 | var getappdata = data["getappdata"] as Dictionary;
96 | var ltc_exchange_rates = getappdata["ltc_exchange_rates"] as Dictionary;
97 | var btc_exchange_rates = getappdata["btc_exchange_rates"] as Dictionary;
98 | var user = getappdata["user"] as Dictionary;
99 | Balance = user["balance_btc"].ExtractDecimal();
100 |
101 | var entry = GetEntry("x11");
102 | if (entry != null)
103 | {
104 | var hashrate = user["hashrate_x11"].ExtractDecimal();
105 | entry.AcceptSpeed = hashrate / 1000;
106 | }
107 |
108 | entry = GetEntry("scrypt");
109 | if (entry != null)
110 | {
111 | var hashrate = user["hashrate_scrypt"].ExtractDecimal();
112 | entry.AcceptSpeed = hashrate / 1000;
113 | }
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/MinerControl/Services/ManualService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using MinerControl.PriceEntries;
6 |
7 | namespace MinerControl.Services
8 | {
9 | public class ManualService : ServiceBase
10 | {
11 | public ManualService()
12 | {
13 | ServiceEnum = ServiceEnum.Manual;
14 | }
15 |
16 | public override void Initialize(IDictionary data)
17 | {
18 | ExtractCommon(data);
19 |
20 | var items = data["algos"] as object[];
21 | foreach (var rawitem in items)
22 | {
23 | var item = rawitem as Dictionary;
24 | var entry = CreateEntry(item);
25 |
26 | if (item.ContainsKey("price"))
27 | entry.Price = item["price"].ExtractDecimal();
28 | if (item.ContainsKey("fee"))
29 | entry.FeePercent = item["fee"].ExtractDecimal();
30 |
31 | Add(entry);
32 | }
33 | }
34 |
35 | public override void CheckPrices()
36 | {
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/MinerControl/Services/NiceHashService.cs:
--------------------------------------------------------------------------------
1 | namespace MinerControl.Services
2 | {
3 | public class NiceHashService : NiceHashServiceBase
4 | {
5 | public NiceHashService()
6 | {
7 | ServiceEnum = ServiceEnum.NiceHash;
8 | }
9 |
10 | protected override string BalanceFormat { get { return "https://www.nicehash.com/api?method=stats.provider&addr={0}"; } }
11 | protected override string CurrentFormat { get { return "https://www.nicehash.com/api?method=stats.global.current"; } }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MinerControl/Services/NiceHashServiceBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using MinerControl.PriceEntries;
5 | using MinerControl.Utility;
6 |
7 | namespace MinerControl.Services
8 | {
9 | public abstract class NiceHashServiceBase : ServiceBase
10 | {
11 | protected abstract string BalanceFormat { get; }
12 | protected abstract string CurrentFormat { get; }
13 |
14 | public NiceHashServiceBase()
15 | {
16 | DonationAccount = "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y";
17 | DonationWorker = "1";
18 | }
19 |
20 | public override void Initialize(IDictionary data)
21 | {
22 | ExtractCommon(data);
23 |
24 | var items = data["algos"] as object[];
25 | foreach (var rawitem in items)
26 | {
27 | var item = rawitem as Dictionary;
28 | var entry = CreateEntry(item);
29 | if (string.IsNullOrWhiteSpace(entry.PriceId))
30 | entry.PriceId = GetAgorithmId(entry.AlgoName).ToString();
31 |
32 | Add(entry);
33 | }
34 | }
35 |
36 | public override void CheckPrices()
37 | {
38 | ClearStalePrices();
39 | WebUtil.DownloadJson(CurrentFormat, ProcessPrices);
40 | WebUtil.DownloadJson(string.Format(BalanceFormat, _account), ProcessBalances);
41 | }
42 |
43 | private void ProcessPrices(object jsonData)
44 | {
45 | var data = jsonData as Dictionary;
46 | var result = data["result"] as Dictionary;
47 | var stats = result["stats"] as object[];
48 |
49 | lock (MiningEngine)
50 | {
51 | foreach (var stat in stats)
52 | {
53 | var item = stat as Dictionary;
54 | var algo = item["algo"].ToString();
55 | var entry = GetEntry(algo);
56 | if (entry == null) continue;
57 |
58 | entry.Price = item["price"].ExtractDecimal();
59 | switch (entry.AlgoName)
60 | {
61 | case "sha256":
62 | entry.Price = item["price"].ExtractDecimal() / 1000; // SHA256 listed in TH/s
63 | break;
64 | default:
65 | entry.Price = item["price"].ExtractDecimal(); // All others in GH/s
66 | break;
67 | }
68 | }
69 |
70 | MiningEngine.PricesUpdated = true;
71 | MiningEngine.HasPrices = true;
72 |
73 | LastUpdated = DateTime.Now;
74 | }
75 | }
76 |
77 | private void ProcessBalances(object jsonData)
78 | {
79 | var totalBalance = 0m;
80 | var data = jsonData as Dictionary;
81 | var result = data["result"] as Dictionary;
82 | var stats = result["stats"] as object[];
83 | foreach (var stat in stats)
84 | {
85 | var item = stat as Dictionary;
86 | totalBalance += item["balance"].ExtractDecimal();
87 | var algo = item["algo"].ToString();
88 | var entry = GetEntry(algo);
89 | if (entry == null) continue;
90 |
91 | entry.Balance = item["balance"].ExtractDecimal();
92 | switch (entry.AlgoName)
93 | {
94 | case "sha256":
95 | entry.AcceptSpeed = item["accepted_speed"].ExtractDecimal();
96 | entry.RejectSpeed = item["rejected_speed"].ExtractDecimal();
97 | break;
98 | default:
99 | entry.AcceptSpeed = item["accepted_speed"].ExtractDecimal() * 1000;
100 | entry.RejectSpeed = item["rejected_speed"].ExtractDecimal() * 1000;
101 | break;
102 | }
103 | }
104 |
105 | lock (MiningEngine)
106 | {
107 | Balance = totalBalance;
108 | }
109 | }
110 |
111 | private IDictionary _algoTranslation = new Dictionary
112 | {
113 | {"x11", 3},
114 | {"x13", 4},
115 | {"scrypt", 0},
116 | {"scryptn", 2},
117 | {"keccak", 5},
118 | {"sha256", 1},
119 | {"x15", 6},
120 | {"nist5", 7},
121 | {"neoscrypt", 8}
122 | };
123 |
124 | private int GetAgorithmId(string algorithmName)
125 | {
126 | return _algoTranslation[algorithmName];
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/MinerControl/Services/ServiceBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using MinerControl.PriceEntries;
5 | using MinerControl.Utility;
6 |
7 | namespace MinerControl.Services
8 | {
9 | public abstract class ServiceBase : PropertyChangedBase, IService
10 | where TEntry : PriceEntryBase, new()
11 | {
12 | private ServiceEnum _serviceEnum;
13 | private DateTime? _lastUpdated;
14 | private decimal _balance;
15 |
16 | public MiningEngine MiningEngine { get; set; }
17 | public ServiceEnum ServiceEnum { get { return _serviceEnum; } protected set { SetField(ref _serviceEnum, value, () => ServiceEnum, () => ServicePrint); } }
18 | public DateTime? LastUpdated { get { return _lastUpdated; } protected set { SetField(ref _lastUpdated, value, () => LastUpdated, () => LastUpdatedPrint); } }
19 | public decimal Balance { get { return _balance; } protected set { SetField(ref _balance, value, () => Balance, () => BalancePrint, () => CurrencyPrint); } }
20 | public decimal Currency { get { return Balance * MiningEngine.Exchange; } }
21 |
22 | public virtual string ServicePrint { get { return ServiceEnum.ToString(); } }
23 | public string LastUpdatedPrint { get { return LastUpdated == null ? string.Empty : LastUpdated.Value.ToString("HH:mm:ss"); } }
24 | public string BalancePrint { get { return Balance == 0.0m ? string.Empty : Balance.ToString("N8"); } }
25 | public string CurrencyPrint { get { return Currency == 0.0m ? string.Empty : Currency.ToString("N4"); } }
26 | public string TimeMiningPrint
27 | {
28 | get
29 | {
30 | var seconds = PriceEntries.Sum(o => o.TimeMiningWithCurrent.TotalSeconds);
31 | return TimeSpan.FromSeconds(seconds).FormatTime(true);
32 | }
33 | }
34 |
35 | public ServiceBase()
36 | {
37 | DonationAccount = string.Empty;
38 | DonationWorker = string.Empty;
39 | }
40 |
41 | public void UpdateTime()
42 | {
43 | OnPropertyChanged(() => TimeMiningPrint);
44 | }
45 |
46 | public void UpdateExchange()
47 | {
48 | OnPropertyChanged(() => CurrencyPrint);
49 | }
50 |
51 | protected IList PriceEntries { get { return MiningEngine.PriceEntries.Where(o => o.ServiceEntry.ServiceEnum == ServiceEnum).Select(o => (TEntry)o).ToList(); } }
52 |
53 | protected string _account;
54 | protected string _worker;
55 | protected string _param1;
56 | protected string _param2;
57 | protected string _param3;
58 | protected decimal _weight = 1.0m;
59 | protected string DonationAccount { get; set;}
60 | protected string DonationWorker { get; set; }
61 | protected IDictionary AlgoTranslations { get; set; }
62 |
63 | public abstract void Initialize(IDictionary data);
64 | public abstract void CheckPrices();
65 |
66 | protected void ExtractCommon(IDictionary data)
67 | {
68 | _account = data.GetString("account") ?? string.Empty;
69 | _worker = data.GetString("worker") ?? string.Empty;
70 | if (data.ContainsKey("weight"))
71 | _weight = data["weight"].ExtractDecimal();
72 | _param1 = data.GetString("sparam1") ?? data.GetString("param1") ?? string.Empty;
73 | _param2 = data.GetString("sparam2") ?? data.GetString("param2") ?? string.Empty;
74 | _param3 = data.GetString("sparam3") ?? data.GetString("param3") ?? string.Empty;
75 | }
76 |
77 | protected string ProcessedSubstitutions(string raw, AlgorithmEntry algo)
78 | {
79 | if (string.IsNullOrWhiteSpace(raw)) return null;
80 | raw = raw
81 | .Replace("_ACCOUNT_", _account)
82 | .Replace("_WORKER_", _worker);
83 | return ProcessCommon(raw, algo);
84 | }
85 |
86 | protected string ProcessedDonationSubstitutions(string raw, AlgorithmEntry algo)
87 | {
88 | if (string.IsNullOrWhiteSpace(raw)) return null;
89 | raw = raw
90 | .Replace("_ACCOUNT_", DonationAccount)
91 | .Replace("_WORKER_", DonationWorker);
92 | return ProcessCommon(raw, algo);
93 | }
94 |
95 | private string ProcessCommon(string raw, AlgorithmEntry algo)
96 | {
97 | return raw
98 | .Replace("_PARAM1_", _param1)
99 | .Replace("_PARAM2_", _param2)
100 | .Replace("_PARAM3_", _param3)
101 | .Replace("_SPARAM1_", _param1)
102 | .Replace("_SPARAM2_", _param2)
103 | .Replace("_SPARAM3_", _param3)
104 | .Replace("_APARAM1_", algo.Param1)
105 | .Replace("_APARAM2_", algo.Param2)
106 | .Replace("_APARAM3_", algo.Param3);
107 | }
108 |
109 | protected TEntry CreateEntry(Dictionary item)
110 | {
111 | var entry = new TEntry();
112 | entry.MiningEngine = MiningEngine;
113 | entry.ServiceEntry = this;
114 |
115 | entry.AlgoName = item.GetString("algo");
116 | var algo = MiningEngine.AlgorithmEntries.Single(o => o.Name == entry.AlgoName);
117 | entry.Name = algo.Display;
118 | entry.PriceId = item.GetString("priceid");
119 | entry.Hashrate = algo.Hashrate;
120 | entry.Power = algo.Power;
121 | entry.Weight = _weight;
122 | entry.Folder = ProcessedSubstitutions(item.GetString("folder"), algo) ?? string.Empty;
123 | entry.Command = ProcessedSubstitutions(item.GetString("command"), algo);
124 | entry.Arguments = ProcessedSubstitutions(item.GetString("arguments"), algo) ?? string.Empty;
125 | if(item.ContainsKey("usewindow"))
126 | entry.UseWindow = bool.Parse(item["usewindow"].ToString());
127 | if (!string.IsNullOrWhiteSpace(DonationAccount))
128 | {
129 | entry.DonationFolder = ProcessedDonationSubstitutions(item.GetString("folder"), algo) ?? string.Empty;
130 | entry.DonationCommand = ProcessedDonationSubstitutions(item.GetString("command"), algo);
131 | entry.DonationArguments = ProcessedDonationSubstitutions(item.GetString("arguments"), algo) ?? string.Empty;
132 | }
133 |
134 | return entry;
135 | }
136 |
137 | protected void Add(TEntry entry)
138 | {
139 | MiningEngine.PriceEntries.Add(entry);
140 | }
141 |
142 | private string GetAlgoName(string name)
143 | {
144 | if (AlgoTranslations == null || !AlgoTranslations.ContainsKey(name)) return name;
145 | return AlgoTranslations[name];
146 | }
147 |
148 | protected TEntry GetEntry(string algo)
149 | {
150 | return PriceEntries.FirstOrDefault(o => (o.PriceId != null && o.PriceId == algo) || (o.PriceId == null && o.AlgoName == GetAlgoName(algo)));
151 | }
152 |
153 | protected void ClearStalePrices()
154 | {
155 | if (!LastUpdated.HasValue || LastUpdated.Value.AddMinutes(30) > DateTime.Now) return;
156 |
157 | foreach (var entry in PriceEntries)
158 | entry.Price = 0;
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/MinerControl/Services/TradeMyBitService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using MinerControl.PriceEntries;
5 | using MinerControl.Utility;
6 |
7 | namespace MinerControl.Services
8 | {
9 | public class TradeMyBitService : ServiceBase
10 | {
11 | // https://pool.trademybit.com/api/bestalgo?key=[key]
12 | // [{"algo":"x11","score":"0.00136681","actual":"0.000248511"},{"algo":"nscrypt","score":"0.00111675","actual":"0.00237607"},{"algo":"scrypt","score":"0.000443541","actual":"0.000443541"},{"algo":"nist5","score":"0.0000663135","actual":"0.000004019"},{"algo":"x13","score":"0.0000659915","actual":"0.0000178355"}]
13 |
14 | // https://pool.trademybit.com/api/balance?key=[key]
15 | // {"autoexchange":{"est_total":"0.00130840","unexchanged":"0.00000000","exchanged":"0.00130840","alltime":"0.00000000"}}
16 |
17 | private string _apikey;
18 |
19 | public TradeMyBitService()
20 | {
21 | ServiceEnum = ServiceEnum.TradeMyBit;
22 | DonationAccount = "MinerControl";
23 | DonationWorker = "1";
24 |
25 | AlgoTranslations = new Dictionary
26 | {
27 | {"nscrypt", "scryptn"}
28 | };
29 | }
30 |
31 | public override void Initialize(IDictionary data)
32 | {
33 | ExtractCommon(data);
34 | _apikey = data.GetString("apikey");
35 |
36 | var items = data["algos"] as object[];
37 | foreach (var rawitem in items)
38 | {
39 | var item = rawitem as Dictionary;
40 | var entry = CreateEntry(item);
41 | Add(entry);
42 | }
43 | }
44 |
45 | public override void CheckPrices()
46 | {
47 | ClearStalePrices();
48 | WebUtil.DownloadJson(string.Format("https://pool.trademybit.com/api/bestalgo?key={0}", _apikey), ProcessPrices);
49 | WebUtil.DownloadJson(string.Format("https://pool.trademybit.com/api/balance?key={0}", _apikey), ProcessBalances);
50 | }
51 |
52 | private void ProcessPrices(object jsonData)
53 | {
54 | var data = jsonData as object[];
55 | lock (MiningEngine)
56 | {
57 | foreach (var rawitem in data)
58 | {
59 | var item = rawitem as Dictionary;
60 | var algo = item.GetString("algo");
61 | var entry = GetEntry(algo);
62 | if (entry == null) continue;
63 |
64 | entry.Price = item["actual"].ExtractDecimal() * 1000;
65 | }
66 |
67 | MiningEngine.PricesUpdated = true;
68 | MiningEngine.HasPrices = true;
69 |
70 | LastUpdated = DateTime.Now;
71 | }
72 | }
73 |
74 | private void ProcessBalances(object jsonData)
75 | {
76 | var data = jsonData as Dictionary;
77 | var balances = data["autoexchange"] as Dictionary;
78 |
79 | lock (MiningEngine)
80 | {
81 | Balance = balances["est_total"].ExtractDecimal();
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/MinerControl/Services/WafflePoolService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using MinerControl.PriceEntries;
5 | using MinerControl.Utility;
6 |
7 | namespace MinerControl.Services
8 | {
9 | public class WafflePoolService : ServiceBase
10 | {
11 | // http://wafflepool.com/api/stats
12 | // {"scrypt":{
13 | // "mining":"hidden",
14 | // "hashrate":22229349799,
15 | // "last_hour":{"aricoin":1.69,"feathercoin":20.61,"litecoin":31.07,"litecoindark":2.32,"megacoin":6.69,"monacoin":3.19,"nautiluscoin":5.7,"noblecoin":4.56,"potcoin":3.29,"tagcoin":3.44,"usde":3.79,"viacoin":13.66},
16 | // "balances":{"sent":15957.24412827,"exchanged":5.5655921,"confirmed":2.3906955,"unconfirmed":1.49996499},
17 | // "earnings":[
18 | // {"date":"2014-10-06","earned":3.65661792,"hashrate":22652460350,"permhs":0.00036595,"vsltc":116.02},
19 | // {"date":"2014-10-05","earned":7.3391845,"hashrate":22683413258,"permhs":0.00032355,"vsltc":100.25},
20 | // {"date":"2014-10-04","earned":8.25865688,"hashrate":20843006208,"permhs":0.00039623,"vsltc":123.13},
21 | // {"date":"2014-10-03","earned":6.38886382,"hashrate":16476333450,"permhs":0.00038776,"vsltc":121.41},
22 | // {"date":"2014-10-02","earned":6.67626292,"hashrate":22812053995,"permhs":0.00029266,"vsltc":89.81},
23 | // {"date":"2014-10-01","earned":7.99719669,"hashrate":11478782808,"permhs":0.00069669,"vsltc":212.72},
24 | // {"date":"2014-09-30","earned":5.90335632,"hashrate":15462069191,"permhs":0.0003818,"vsltc":117.91}]},
25 | // "nscrypt":{
26 | // "mining":"murraycoin","hashrate":159737729,"last_hour":{"murraycoin":2.61,"spaincoin":3.52,"vertcoin":93.87},"balances":{"sent":156.60008804,"exchanged":0.15470803,"confirmed":0,"unconfirmed":0.04396441},"earnings":[{"date":"2014-10-06","earned":0.08699461,"hashrate":158068034,"permhs":0.0012477,"vsltc":185.92},{"date":"2014-10-05","earned":0.23894878,"hashrate":171170636,"permhs":0.00139597,"vsltc":203.28},{"date":"2014-10-04","earned":0.30048782,"hashrate":198166747,"permhs":0.00151634,"vsltc":221.46},{"date":"2014-10-03","earned":0.34351864,"hashrate":204521631,"permhs":0.00167962,"vsltc":247.16},{"date":"2014-10-02","earned":0.46233947,"hashrate":240756592,"permhs":0.00192036,"vsltc":276.99},{"date":"2014-10-01","earned":0.38214958,"hashrate":248980112,"permhs":0.00153486,"vsltc":220.26},{"date":"2014-09-30","earned":0.42550327,"hashrate":254810422,"permhs":0.00166988,"vsltc":242.38}]},
27 | // "x11":{
28 | // "mining":"startcoinv2","hashrate":18529509790,"last_hour":{"cannabiscoin":5.93,"cryptcoin":0.21,"darkcoin":8.47,"fractalcoin":0.13,"glyphcoin":0.19,"startcoinv2":81.72,"urocoin":3.19,"virtualcoin":0.15},"balances":{"sent":1058.00456076,"exchanged":5.22549376,"confirmed":0.02933664,"unconfirmed":0.08405081},"earnings":[{"date":"2014-10-06","earned":4.3002266,"hashrate":17715027860,"permhs":0.00055032,"vsltc":697.88},{"date":"2014-10-05","earned":8.16684463,"hashrate":16683302480,"permhs":0.00048952,"vsltc":606.68},{"date":"2014-10-04","earned":6.19759441,"hashrate":15926108606,"permhs":0.00038915,"vsltc":483.71},{"date":"2014-10-03","earned":5.38855032,"hashrate":15966248607,"permhs":0.0003375,"vsltc":422.67},{"date":"2014-10-02","earned":3.92883941,"hashrate":14658970986,"permhs":0.00026802,"vsltc":329},{"date":"2014-10-01","earned":2.82580133,"hashrate":12714976659,"permhs":0.00022224,"vsltc":271.43},{"date":"2014-09-30","earned":3.05441985,"hashrate":14278611823,"permhs":0.00021392,"vsltc":264.25}]},
29 | // "x13":{
30 | // "mining":null,"hashrate":10995107,"last_hour":[],"balances":{"sent":138.95795525,"exchanged":0.04238868,"confirmed":0,"unconfirmed":0},"earnings":[{"date":"2014-10-06","earned":0,"hashrate":0,"permhs":0,"vsltc":0},{"date":"2014-10-05","earned":0,"hashrate":0,"permhs":0,"vsltc":0},{"date":"2014-10-04","earned":0,"hashrate":0,"permhs":0,"vsltc":0},{"date":"2014-10-03","earned":0,"hashrate":0,"permhs":0,"vsltc":0},{"date":"2014-10-02","earned":0,"hashrate":0,"permhs":0,"vsltc":0},{"date":"2014-10-01","earned":0,"hashrate":0,"permhs":0,"vsltc":0},{"date":"2014-09-30","earned":0,"hashrate":0,"permhs":0,"vsltc":0}]}}
31 |
32 | // http://wafflepool.com/api/miner?address=1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y
33 | // {"scrypt":{"hashrate":0,"hashrate_str":"0.00 kH\/s","stalerate":0,"stalerate_str":"0.00 kH\/s","workers":[],"balances":{"sent":0,"confirmed":0,"unconverted":0}},
34 | // "nscrypt":{"hashrate":0,"hashrate_str":"0.00 kH\/s","stalerate":0,"stalerate_str":"0.00 kH\/s","workers":[],"balances":{"sent":0,"confirmed":0,"unconverted":0}},
35 | // "x11":{
36 | // "hashrate":1215199,"hashrate_str":"1.22 MH\/s","stalerate":0,"stalerate_str":"0.00 kH\/s",
37 | // "workers":{"1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y":{"hashrate":1215199,"stalerate":0,"str":"1.22 MH\/s","last_seen":1412633470}},
38 | // "balances":{"sent":0,"confirmed":0,"unconverted":0}},
39 | // "x13":{"hashrate":0,"hashrate_str":"0.00 kH\/s","stalerate":0,"stalerate_str":"0.00 kH\/s","workers":[],"balances":{"sent":0,"confirmed":0,"unconverted":0}}}
40 |
41 | public WafflePoolService()
42 | {
43 | ServiceEnum = ServiceEnum.WafflePool;
44 | DonationAccount = "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y";
45 | DonationWorker = "1";
46 |
47 | AlgoTranslations = new Dictionary
48 | {
49 | {"nscrypt", "scryptn"}
50 | };
51 | }
52 |
53 | public override void Initialize(IDictionary data)
54 | {
55 | ExtractCommon(data);
56 |
57 | var items = data["algos"] as object[];
58 | foreach (var rawitem in items)
59 | {
60 | var item = rawitem as Dictionary;
61 | var entry = CreateEntry(item);
62 |
63 | Add(entry);
64 | }
65 | }
66 |
67 | public override void CheckPrices()
68 | {
69 | ClearStalePrices();
70 | WebUtil.DownloadJson("http://wafflepool.com/api/stats", ProcessPrices);
71 | WebUtil.DownloadJson(string.Format("http://wafflepool.com/api/miner?address={0}", _account), ProcessBalances);
72 | }
73 |
74 | private void ProcessPrices(object jsonData)
75 | {
76 | var data = jsonData as Dictionary;
77 | lock (MiningEngine)
78 | {
79 | foreach (var key in data.Keys)
80 | {
81 | var rawitem = data[key];
82 | var item = rawitem as Dictionary;
83 |
84 | var entry = GetEntry(key.ToLower());
85 | if (entry == null) continue;
86 |
87 | var earnings = item["earnings"] as object[];
88 | var earning = earnings[0] as Dictionary;
89 |
90 | entry.Price = earning["permhs"].ExtractDecimal() * 1000;
91 | }
92 |
93 | MiningEngine.PricesUpdated = true;
94 | MiningEngine.HasPrices = true;
95 |
96 | LastUpdated = DateTime.Now;
97 | }
98 | }
99 |
100 | private void ProcessBalances(object jsonData)
101 | {
102 | var data = jsonData as Dictionary;
103 |
104 | lock (MiningEngine)
105 | {
106 | foreach (var entry in PriceEntries)
107 | {
108 | entry.Balance = 0;
109 | entry.AcceptSpeed = 0;
110 | entry.RejectSpeed = 0;
111 | }
112 |
113 | foreach (var key in data.Keys)
114 | {
115 | var rawitem = data[key];
116 | var item = rawitem as Dictionary;
117 |
118 | var entry = GetEntry(key.ToLower());
119 | if (entry == null) continue;
120 |
121 | entry.AcceptSpeed = item["hashrate"].ExtractDecimal() / 1000000;
122 | entry.RejectSpeed = item["stalerate"].ExtractDecimal() / 1000000;
123 |
124 | var balances = item["balances"] as Dictionary;
125 | entry.Balance = balances["confirmed"].ExtractDecimal() + balances["unconverted"].ExtractDecimal();
126 | }
127 |
128 | Balance = PriceEntries.Select(o => o.Balance).Sum();
129 |
130 | MiningEngine.PricesUpdated = true;
131 | }
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/MinerControl/Services/WePayBtcService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using MinerControl.PriceEntries;
6 | using MinerControl.Utility;
7 |
8 | namespace MinerControl.Services
9 | {
10 | public class WePayBtcService : ServiceBase
11 | {
12 | // http://wepaybtc.com/payouts.json
13 |
14 | //{
15 | // "reference": 0.001,
16 | // "x11": 0.0002066,
17 | // "x13": 0.0002985,
18 | // "x15": 0.0003717,
19 | // "nist5": 0.00006863
20 | //}
21 |
22 | public WePayBtcService()
23 | {
24 | ServiceEnum = ServiceEnum.WePayBTC;
25 | DonationAccount = "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y";
26 | }
27 |
28 | public override void Initialize(IDictionary data)
29 | {
30 | ExtractCommon(data);
31 |
32 | var items = data["algos"] as object[];
33 | foreach (var rawitem in items)
34 | {
35 | var item = rawitem as Dictionary;
36 | var entry = CreateEntry(item);
37 |
38 | Add(entry);
39 | }
40 | }
41 |
42 | public override void CheckPrices()
43 | {
44 | ClearStalePrices();
45 | WebUtil.DownloadJson("http://wepaybtc.com/payouts.json", ProcessPrices);
46 | }
47 |
48 | private void ProcessPrices(object jsonData)
49 | {
50 | var data = jsonData as Dictionary;
51 |
52 | lock (MiningEngine)
53 | {
54 | foreach (var key in data.Keys)
55 | {
56 | var rawitem = data[key];
57 | var item = rawitem as Dictionary;
58 | var algo = key.ToLower();
59 |
60 | var entry = GetEntry(algo);
61 | if (entry == null) continue;
62 |
63 | entry.Price = data[key].ExtractDecimal() * 1000;
64 | }
65 |
66 | MiningEngine.PricesUpdated = true;
67 | MiningEngine.HasPrices = true;
68 |
69 | LastUpdated = DateTime.Now;
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/MinerControl/Services/WestHashService.cs:
--------------------------------------------------------------------------------
1 | namespace MinerControl.Services
2 | {
3 | public class WestHashService : NiceHashServiceBase
4 | {
5 | public WestHashService()
6 | {
7 | ServiceEnum = ServiceEnum.WestHash;
8 | }
9 |
10 | protected override string BalanceFormat { get { return "https://www.westhash.com/api?method=stats.provider&addr={0}"; } }
11 | protected override string CurrentFormat { get { return "https://www.westhash.com/api?method=stats.global.current"; } }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MinerControl/Services/YaampService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using MinerControl.PriceEntries;
5 | using MinerControl.Utility;
6 |
7 | namespace MinerControl.Services
8 | {
9 | public class YaampService : ServiceBase
10 | {
11 | // http://yaamp.com/api/status
12 | // {
13 | // "scrypt": {"name": "scrypt", "port": 3433, "coins": 21, "fees": 0.5, "hashrate": 1585708947, "estimate_current": 0.00017441, "estimate_last24h": 0.00018214, "actual_last24h": 0.00019935},
14 | // "scryptn": {"name": "scryptn", "port": 4333, "coins": 3, "fees": 3.2, "hashrate": 88775354, "estimate_current": 0.00042183, "estimate_last24h": 0.00045701, "actual_last24h": 0.00039583},
15 | // "neoscrypt": {"name": "neoscrypt", "port": 4233, "coins": 4, "fees": 2.8, "hashrate": 359254951, "estimate_current": 0.00217158, "estimate_last24h": 0.00352892, "actual_last24h": 0.00320471},
16 | // "quark": {"name": "quark", "port": 4033, "coins": 3, "fees": 0.5, "hashrate": 85473584, "estimate_current": 0.00000078, "estimate_last24h": 0.00000087, "actual_last24h": 0.00020362},
17 | // "lyra2": {"name": "lyra2", "port": 4433, "coins": 1, "fees": 0.6, "hashrate": 16864909, "estimate_current": 0.00062095, "estimate_last24h": 0.00063257, "actual_last24h": 0.00090811},
18 | // "x11": {"name": "x11", "port": 3533, "coins": 10, "fees": 1.3, "hashrate": 7793602368, "estimate_current": 0.00019716, "estimate_last24h": 0.00015537, "actual_last24h": 0.00016760},
19 | // "x13": {"name": "x13", "port": 3633, "coins": 2, "fees": 3.7, "hashrate": 2500273917, "estimate_current": 0.00019537, "estimate_last24h": 0.00016803, "actual_last24h": 0.00017710},
20 | // "x14": {"name": "x14", "port": 3933, "coins": 1, "fees": 3.5, "hashrate": 54660672, "estimate_current": 0.00032863, "estimate_last24h": 0.00025539, "actual_last24h": 0.00025089},
21 | // "x15": {"name": "x15", "port": 3733, "coins": 3, "fees": 5.4, "hashrate": 5870269795, "estimate_current": 0.00126368, "estimate_last24h": 0.00025544, "actual_last24h": 0.00082305}
22 | // }
23 |
24 | private int _priceMode;
25 |
26 | public YaampService()
27 | {
28 | ServiceEnum = ServiceEnum.YAAMP;
29 | DonationAccount = "1PMj3nrVq5CH4TXdJSnHHLPdvcXinjG72y";
30 | }
31 |
32 | public override void Initialize(IDictionary data)
33 | {
34 | ExtractCommon(data);
35 |
36 | if (data.ContainsKey("pricemode"))
37 | _priceMode = int.Parse(data["pricemode"].ToString());
38 |
39 | var items = data["algos"] as object[];
40 | foreach (var rawitem in items)
41 | {
42 | var item = rawitem as Dictionary;
43 | var entry = CreateEntry(item);
44 |
45 | Add(entry);
46 | }
47 | }
48 |
49 | public override void CheckPrices()
50 | {
51 | ClearStalePrices();
52 | WebUtil.DownloadJson("http://yaamp.com/api/status", ProcessPrices);
53 | WebUtil.DownloadJson(string.Format("http://yaamp.com/api/wallet?address={0}", _account), ProcessBalances);
54 | }
55 |
56 | private void ProcessPrices(object jsonData)
57 | {
58 | var data = jsonData as Dictionary;
59 |
60 | lock (MiningEngine)
61 | {
62 | foreach (var key in data.Keys)
63 | {
64 | var rawitem = data[key];
65 | var item = rawitem as Dictionary;
66 | var algo = key.ToLower();
67 |
68 | var entry = GetEntry(algo);
69 | if (entry == null) continue;
70 |
71 | switch (_priceMode)
72 | {
73 | case 1:
74 | entry.Price = item["estimate_last24h"].ExtractDecimal() * 1000;
75 | break;
76 | case 2:
77 | entry.Price = item["actual_last24h"].ExtractDecimal() * 1000;
78 | break;
79 | default:
80 | entry.Price = item["estimate_current"].ExtractDecimal() * 1000;
81 | break;
82 | }
83 | entry.FeePercent = item["fees"].ExtractDecimal();
84 | }
85 |
86 | MiningEngine.PricesUpdated = true;
87 | MiningEngine.HasPrices = true;
88 |
89 | LastUpdated = DateTime.Now;
90 | }
91 | }
92 |
93 | private void ProcessBalances(object jsonData)
94 | {
95 | var data = jsonData as Dictionary;
96 |
97 | lock (MiningEngine)
98 | {
99 | Balance = data["unpaid"].ExtractDecimal();
100 |
101 | foreach (var entry in PriceEntries)
102 | entry.AcceptSpeed = 0;
103 |
104 | if (!data.ContainsKey("miners")) return;
105 | var miners = data["miners"] as Dictionary;
106 | foreach (var key in miners.Keys)
107 | {
108 | var entry = GetEntry(key.ToLower());
109 | if (entry == null) continue;
110 | var item = miners[key] as Dictionary;
111 | entry.AcceptSpeed = item["hashrate"].ExtractDecimal() / 1000000;
112 | }
113 |
114 | MiningEngine.PricesUpdated = true;
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/MinerControl/Utility/ErrorLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace MinerControl.Utility
6 | {
7 | public static class ErrorLogger
8 | {
9 | const string logfile = "error.log";
10 |
11 | public static bool LogExceptions { get; set; }
12 |
13 | public static void Log(Exception ex)
14 | {
15 | var sb = new StringBuilder();
16 | sb.AppendLine();
17 | sb.AppendLine(DateTime.Now.ToString());
18 | sb.AppendLine("----------------------------------------------");
19 | sb.AppendLine(string.Format("Type: {0}", ex.GetType().Name));
20 | sb.AppendLine(string.Format("Message: {0}", ex.Message));
21 | sb.AppendLine(string.Format("Stack trace: {0}", ex.StackTrace));
22 |
23 | using (var w = File.Exists(logfile) ? File.AppendText(logfile) : File.CreateText(logfile))
24 | {
25 | w.Write(sb.ToString());
26 | }
27 |
28 | if (ex.InnerException != null)
29 | Log(ex.InnerException);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/MinerControl/Utility/Multicast/MulticastDataReceivedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace MinerControl.Utility.Multicast
8 | {
9 | public class MulticastDataReceivedEventArgs : EventArgs
10 | {
11 | private byte[] _data;
12 | private IPEndPoint _remote;
13 |
14 | public MulticastDataReceivedEventArgs(IPEndPoint remote, byte[] data)
15 | {
16 | _remote = remote;
17 | _data = data;
18 | }
19 |
20 | public IPEndPoint RemoteEndPoint { get { return _remote; } }
21 | public byte[] Data { get { return _data; } }
22 | public string StringData { get { return Encoding.Unicode.GetString(_data); } }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/MinerControl/Utility/Multicast/MulticastReceiver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 | using System.Threading;
8 |
9 | namespace MinerControl.Utility.Multicast
10 | {
11 | public delegate void MulticastDataReceivedEventHandler(object sender, MulticastDataReceivedEventArgs e);
12 |
13 | public class MulticastReceiver : IDisposable
14 | {
15 | private Thread _listener;
16 | private IPEndPoint _endPoint;
17 |
18 | public event MulticastDataReceivedEventHandler DataReceived;
19 |
20 | public MulticastReceiver(IPEndPoint endPoint)
21 | {
22 | _endPoint = endPoint;
23 | }
24 |
25 | public void Start()
26 | {
27 | _listener = new Thread(new ThreadStart(BackgroundListener))
28 | {
29 | IsBackground = true
30 | };
31 | _listener.Start();
32 | }
33 |
34 | public void Stop()
35 | {
36 | lock (this)
37 | {
38 | _listener.Abort();
39 | _listener.Join(500);
40 | }
41 | }
42 |
43 | private void BackgroundListener()
44 | {
45 | var bindingEndpoint = new IPEndPoint(IPAddress.Any, _endPoint.Port);
46 | using (var client = new UdpClient())
47 | {
48 | client.ExclusiveAddressUse = false;
49 | client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
50 | client.Client.Bind(bindingEndpoint);
51 | client.JoinMulticastGroup(_endPoint.Address);
52 |
53 | var keepRunning = true;
54 | while (keepRunning)
55 | {
56 | try
57 | {
58 | IPEndPoint remote = new IPEndPoint(IPAddress.Any, _endPoint.Port);
59 | var buffer = client.Receive(ref remote);
60 | lock (this)
61 | {
62 | DataReceived(this, new MulticastDataReceivedEventArgs(remote, buffer));
63 | }
64 | }
65 | catch (ThreadAbortException)
66 | {
67 | keepRunning = false;
68 | Thread.ResetAbort();
69 | }
70 | }
71 |
72 | client.DropMulticastGroup(_endPoint.Address);
73 | }
74 | }
75 |
76 | private bool _disposed;
77 |
78 | public void Dispose()
79 | {
80 | if (_disposed) return;
81 | if (_listener.IsAlive)
82 | {
83 | Stop();
84 | }
85 | _disposed = true;
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/MinerControl/Utility/Multicast/MulticastSender.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 |
8 | namespace MinerControl.Utility.Multicast
9 | {
10 | public class MulticastSender : IDisposable
11 | {
12 | private IPEndPoint _endPoint;
13 | private int _timeToLive;
14 | private UdpClient _udpClient;
15 |
16 | public MulticastSender(IPEndPoint endPoint, int timeToLive)
17 | {
18 | _endPoint = endPoint;
19 | _timeToLive = timeToLive;
20 | }
21 |
22 | public void Start()
23 | {
24 | var bindingEndpoint = new IPEndPoint(IPAddress.Any, _endPoint.Port);
25 |
26 | _udpClient = new UdpClient();
27 | _udpClient.ExclusiveAddressUse = false;
28 | _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
29 | _udpClient.Client.Bind(bindingEndpoint);
30 | _udpClient.JoinMulticastGroup(_endPoint.Address, _timeToLive);
31 | }
32 |
33 | public void Stop()
34 | {
35 | _udpClient.DropMulticastGroup(_endPoint.Address);
36 | _udpClient.Close();
37 | _udpClient = null;
38 | }
39 |
40 | public void Send(byte[] data)
41 | {
42 | _udpClient.Send(data, data.Length, _endPoint);
43 | }
44 |
45 | public void Send(string data)
46 | {
47 | Send(Encoding.Unicode.GetBytes(data));
48 | }
49 |
50 | private bool _disposed;
51 |
52 | public void Dispose()
53 | {
54 | if (_disposed) return;
55 | if (_udpClient != null)
56 | {
57 | Stop();
58 | }
59 | _disposed = true;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/MinerControl/Utility/ProcessUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Management;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 |
9 | namespace MinerControl.Utility
10 | {
11 | public static class ProcessUtil
12 | {
13 | ///
14 | /// Kill a process, and all of its children, grandchildren, etc.
15 | ///
16 | /// Process ID.
17 | public static void KillProcessAndChildren(int pid)
18 | {
19 | ManagementObjectSearcher searcher = new ManagementObjectSearcher
20 | ("Select * From Win32_Process Where ParentProcessID=" + pid);
21 | ManagementObjectCollection moc = searcher.Get();
22 | foreach (ManagementObject mo in moc)
23 | {
24 | KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
25 | }
26 | try
27 | {
28 | Process proc = Process.GetProcessById(pid);
29 | proc.Kill();
30 | }
31 | catch (ArgumentException)
32 | {
33 | // Process already exited.
34 | }
35 | catch (Exception ex)
36 | {
37 | ErrorLogger.Log(ex);
38 | }
39 | }
40 |
41 | public static void KillProcess(Process process)
42 | {
43 | try
44 | {
45 | if (process == null || process.HasExited == true)
46 | return;
47 |
48 | process.Kill();
49 | }
50 | catch (ArgumentException)
51 | {
52 | // Process already exited.
53 | }
54 | catch (Exception ex)
55 | {
56 | ErrorLogger.Log(ex);
57 | }
58 | }
59 |
60 | //http://stackoverflow.com/questions/2647820/toggle-process-startinfo-windowstyle-processwindowstyle-hidden-at-runtime
61 | [DllImport("user32.dll")]
62 | static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
63 |
64 | public static void HideWindow(Process process)
65 | {
66 | if (process == null || process.HasExited) return;
67 | ShowWindow(process.MainWindowHandle, 0); // Hidden
68 | }
69 |
70 | public static void MinimizeWindow(Process process)
71 | {
72 | if (process == null || process.HasExited) return;
73 | ShowWindow(process.MainWindowHandle, 2); // Minimized
74 | }
75 |
76 | [DllImport("user32.dll")]
77 | static extern int SetWindowText(IntPtr hWnd, string text);
78 |
79 | public static void SetWindowTitle(Process process, string title)
80 | {
81 | SetWindowText(process.MainWindowHandle, title);
82 | }
83 |
84 | ///
85 | /// Safely check if process exists and has not exited.
86 | ///
87 | public static bool IsRunning(this Process process)
88 | {
89 | try
90 | {
91 | if (process == null || process.HasExited) return false;
92 | }
93 | catch (InvalidOperationException) // Happens if the process did not launch but object still exists
94 | {
95 | return false;
96 | }
97 |
98 | return true;
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/MinerControl/Utility/PropertyChangedBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using System.Text;
7 |
8 | namespace MinerControl.Utility
9 | {
10 | // Adapted from examples here:
11 | // http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist
12 | public abstract class PropertyChangedBase : INotifyPropertyChanged
13 | {
14 | public event PropertyChangedEventHandler PropertyChanged;
15 |
16 | protected virtual void OnPropertyChanged(string propertyName)
17 | {
18 | PropertyChangedEventHandler handler = PropertyChanged;
19 | if (handler != null)
20 | handler(this, new PropertyChangedEventArgs(propertyName));
21 | }
22 |
23 | protected virtual void OnPropertyChanged(Expression> selectorExpression)
24 | {
25 | if (selectorExpression == null)
26 | throw new ArgumentNullException("selectorExpression");
27 | var me = selectorExpression.Body as MemberExpression;
28 |
29 | // Nullable properties can be nested inside of a convert function
30 | if (me == null)
31 | {
32 | var ue = selectorExpression.Body as UnaryExpression;
33 | if (ue != null)
34 | {
35 | me = ue.Operand as MemberExpression;
36 | }
37 | }
38 |
39 | if (me == null)
40 | throw new ArgumentException("The body must be a member expression");
41 |
42 | OnPropertyChanged(me.Member.Name);
43 | }
44 |
45 | protected void SetField(ref T field, T value, Expression> selectorExpression, params Expression>[] additonal)
46 | {
47 | if (EqualityComparer.Default.Equals(field, value)) return;
48 | field = value;
49 | OnPropertyChanged(selectorExpression);
50 | foreach (var item in additonal)
51 | OnPropertyChanged(item);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/MinerControl/Utility/SlidingBuffer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 |
4 | namespace MinerControl.Utility
5 | {
6 | // Taken from http://stackoverflow.com/questions/6392516
7 |
8 | public class SlidingBuffer : IEnumerable
9 | {
10 | private readonly Queue _queue;
11 | private readonly int _maxCount;
12 |
13 | public SlidingBuffer(int maxCount)
14 | {
15 | _maxCount = maxCount;
16 | _queue = new Queue(maxCount);
17 | }
18 |
19 | public void Add(T item)
20 | {
21 | if (_queue.Count == _maxCount)
22 | _queue.Dequeue();
23 | _queue.Enqueue(item);
24 | }
25 |
26 | public IEnumerator GetEnumerator()
27 | {
28 | return _queue.GetEnumerator();
29 | }
30 |
31 | IEnumerator IEnumerable.GetEnumerator()
32 | {
33 | return GetEnumerator();
34 | }
35 |
36 | public int Count
37 | {
38 | get { return _queue.Count; }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/MinerControl/Utility/SortableBindingList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace MinerControl.Utility
8 | {
9 | // http://www.martinwilley.com/net/code/forms/sortablebindinglist.html
10 | public class SortableBindingList : BindingList where T : class
11 | {
12 | private bool _isSorted;
13 | private ListSortDirection _sortDirection = ListSortDirection.Ascending;
14 | private PropertyDescriptor _sortProperty;
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public SortableBindingList()
20 | {
21 | }
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// An of items to be contained in the .
27 | public SortableBindingList(IList list)
28 | : base(list)
29 | {
30 | }
31 |
32 | ///
33 | /// Gets a value indicating whether the list supports sorting.
34 | ///
35 | protected override bool SupportsSortingCore
36 | {
37 | get { return true; }
38 | }
39 |
40 | ///
41 | /// Gets a value indicating whether the list is sorted.
42 | ///
43 | protected override bool IsSortedCore
44 | {
45 | get { return _isSorted; }
46 | }
47 |
48 | ///
49 | /// Gets the direction the list is sorted.
50 | ///
51 | protected override ListSortDirection SortDirectionCore
52 | {
53 | get { return _sortDirection; }
54 | }
55 |
56 | ///
57 | /// Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class; otherwise, returns null
58 | ///
59 | protected override PropertyDescriptor SortPropertyCore
60 | {
61 | get { return _sortProperty; }
62 | }
63 |
64 | ///
65 | /// Removes any sort applied with ApplySortCore if sorting is implemented
66 | ///
67 | protected override void RemoveSortCore()
68 | {
69 | _sortDirection = ListSortDirection.Ascending;
70 | _sortProperty = null;
71 | _isSorted = false; //thanks Luca
72 | }
73 |
74 | ///
75 | /// Sorts the items if overridden in a derived class
76 | ///
77 | ///
78 | ///
79 | protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
80 | {
81 | _sortProperty = prop;
82 | _sortDirection = direction;
83 |
84 | List list = Items as List;
85 | if (list == null) return;
86 |
87 | list.Sort(Compare);
88 |
89 | _isSorted = true;
90 | //fire an event that the list has been changed.
91 | OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
92 | }
93 |
94 | private int Compare(T lhs, T rhs)
95 | {
96 | var result = OnComparison(lhs, rhs);
97 | //invert if descending
98 | if (_sortDirection == ListSortDirection.Descending)
99 | result = -result;
100 | return result;
101 | }
102 |
103 | private int OnComparison(T lhs, T rhs)
104 | {
105 | object lhsValue = lhs == null ? null : _sortProperty.GetValue(lhs);
106 | object rhsValue = rhs == null ? null : _sortProperty.GetValue(rhs);
107 | if (lhsValue == null)
108 | {
109 | return (rhsValue == null) ? 0 : -1; //nulls are equal
110 | }
111 | if (rhsValue == null)
112 | {
113 | return 1; //first has value, second doesn't
114 | }
115 | if (lhsValue is IComparable)
116 | {
117 | return ((IComparable)lhsValue).CompareTo(rhsValue);
118 | }
119 | if (lhsValue.Equals(rhsValue))
120 | {
121 | return 0; //both are the same
122 | }
123 | //not comparable, compare ToString
124 | return lhsValue.ToString().CompareTo(rhsValue.ToString());
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/MinerControl/Utility/WebUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Web.Script.Serialization;
7 |
8 | namespace MinerControl.Utility
9 | {
10 | public static class WebUtil
11 | {
12 | public static void DownloadJson(string url, Action